squalid-singularity 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.
Files changed (94) hide show
  1. package/.vscode/extensions.json +4 -0
  2. package/.vscode/launch.json +11 -0
  3. package/.wrangler/tmp/pages-pHhhPx/_routes-0.7693472831665579.json +9 -0
  4. package/.wrangler/tmp/pages-pHhhPx/functions-filepath-routing-config-0.7436749681606077.json +21 -0
  5. package/.wrangler/tmp/pages-pHhhPx/functionsRoutes-0.14872757927825653.mjs +19 -0
  6. package/.wrangler/tmp/pages-pHhhPx/functionsWorker-0.7091847872345003.js +491 -0
  7. package/.wrangler/tmp/pages-yKW4pG/_routes-0.6780167228686584.json +9 -0
  8. package/.wrangler/tmp/pages-yKW4pG/functions-filepath-routing-config-0.6268818876758142.json +21 -0
  9. package/.wrangler/tmp/pages-yKW4pG/functionsRoutes-0.016215448179317304.mjs +19 -0
  10. package/.wrangler/tmp/pages-yKW4pG/functionsWorker-0.29714428274758986.js +491 -0
  11. package/README.md +43 -0
  12. package/astro.config.mjs +26 -0
  13. package/functions/agent/[[path]].ts +9 -0
  14. package/functions/starlight/[[path]].ts +9 -0
  15. package/functions/task/[[path]].ts +9 -0
  16. package/index.html.bak +1755 -0
  17. package/package.json +24 -0
  18. package/public/_redirects +1 -0
  19. package/public/art/hero.webp +0 -0
  20. package/public/favicon.ico +0 -0
  21. package/public/favicon.svg +5 -0
  22. package/public/images/generated/01-red-cube-editorial.png +0 -0
  23. package/public/images/generated/02-hero-network.png +0 -0
  24. package/public/images/generated/03-protocol-vault.png +0 -0
  25. package/public/images/generated/04-token-flow.png +0 -0
  26. package/public/images/generated/05-how-escrow.png +0 -0
  27. package/public/images/generated/06-agent-robot.png +0 -0
  28. package/public/images/generated/video-final/music-v1.mp3 +0 -0
  29. package/public/images/generated/video-final/music.mp3 +0 -0
  30. package/public/images/hero-bg.png +0 -0
  31. package/public/images/hero-bg.webp +0 -0
  32. package/public/logo-white-bg.png +0 -0
  33. package/public/logo-white-bg.svg +5 -0
  34. package/public/logo-white.png +0 -0
  35. package/public/logo-white.svg +4 -0
  36. package/public/logo.png +0 -0
  37. package/public/og/agents.png +0 -0
  38. package/public/og/blog-final-chapter.png +0 -0
  39. package/public/og/blog-mandate-vs-virtuals.png +0 -0
  40. package/public/og/blog.png +0 -0
  41. package/public/og/dashboard.png +0 -0
  42. package/public/og/docs.png +0 -0
  43. package/public/og/home.png +0 -0
  44. package/public/og/how.png +0 -0
  45. package/public/og/leaderboard.png +0 -0
  46. package/public/og/protocol.png +0 -0
  47. package/public/og/tasks.png +0 -0
  48. package/public/og/token.png +0 -0
  49. package/public/og/updates.png +0 -0
  50. package/public/skill.md +427 -0
  51. package/public/skills/conway.md +311 -0
  52. package/public/twitter-header.png +0 -0
  53. package/public/twitter-header.svg +51 -0
  54. package/src/components/AgentGridCard.astro +99 -0
  55. package/src/components/AgentRow.astro +57 -0
  56. package/src/components/ColorBends.tsx +306 -0
  57. package/src/components/Footer.astro +45 -0
  58. package/src/components/GigCard.astro +36 -0
  59. package/src/components/Navbar.astro +244 -0
  60. package/src/components/ReviewCard.astro +29 -0
  61. package/src/components/SkillPill.astro +19 -0
  62. package/src/components/StarlightChat.tsx +359 -0
  63. package/src/components/StatusBadge.astro +28 -0
  64. package/src/components/TaskEntry.astro +98 -0
  65. package/src/layouts/Layout.astro +233 -0
  66. package/src/lib/api.ts +365 -0
  67. package/src/pages/404.astro +33 -0
  68. package/src/pages/admin.astro +495 -0
  69. package/src/pages/agent/[...id].astro +1055 -0
  70. package/src/pages/agents/index.astro +309 -0
  71. package/src/pages/blog/conway-automaton.astro +192 -0
  72. package/src/pages/blog/index.astro +49 -0
  73. package/src/pages/blog/mandate-vs-virtuals.astro +542 -0
  74. package/src/pages/blog/the-final-chapter.astro +329 -0
  75. package/src/pages/bounties/index.astro +260 -0
  76. package/src/pages/dashboard.astro +364 -0
  77. package/src/pages/docs.astro +220 -0
  78. package/src/pages/gigs/index.astro +215 -0
  79. package/src/pages/how.astro +172 -0
  80. package/src/pages/index.astro +513 -0
  81. package/src/pages/leaderboard.astro +228 -0
  82. package/src/pages/og/home.astro +65 -0
  83. package/src/pages/protocol/stats.astro +845 -0
  84. package/src/pages/protocol.astro +422 -0
  85. package/src/pages/starlight.astro +13 -0
  86. package/src/pages/task/[...id].astro +1656 -0
  87. package/src/pages/tasks.astro +12 -0
  88. package/src/pages/terms.astro +133 -0
  89. package/src/pages/token.astro +268 -0
  90. package/src/pages/updates.astro +180 -0
  91. package/src/styles/global.css +128 -0
  92. package/tailwind.config.mjs +51 -0
  93. package/tsconfig.json +14 -0
  94. package/wrangler.toml +5 -0
@@ -0,0 +1,306 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import * as THREE from 'three';
3
+
4
+ const MAX_COLORS = 8;
5
+
6
+ const frag = `
7
+ #define MAX_COLORS ${MAX_COLORS}
8
+ uniform vec2 uCanvas;
9
+ uniform float uTime;
10
+ uniform float uSpeed;
11
+ uniform vec2 uRot;
12
+ uniform int uColorCount;
13
+ uniform vec3 uColors[MAX_COLORS];
14
+ uniform int uTransparent;
15
+ uniform float uScale;
16
+ uniform float uFrequency;
17
+ uniform float uWarpStrength;
18
+ uniform vec2 uPointer; // in NDC [-1,1]
19
+ uniform float uMouseInfluence;
20
+ uniform float uParallax;
21
+ uniform float uNoise;
22
+ varying vec2 vUv;
23
+
24
+ void main() {
25
+ float t = uTime * uSpeed;
26
+ vec2 p = vUv * 2.0 - 1.0;
27
+ p += uPointer * uParallax * 0.1;
28
+ vec2 rp = vec2(p.x * uRot.x - p.y * uRot.y, p.x * uRot.y + p.y * uRot.x);
29
+ vec2 q = vec2(rp.x * (uCanvas.x / uCanvas.y), rp.y);
30
+ q /= max(uScale, 0.0001);
31
+ q /= 0.5 + 0.2 * dot(q, q);
32
+ q += 0.2 * cos(t) - 7.56;
33
+ vec2 toward = (uPointer - rp);
34
+ q += toward * uMouseInfluence * 0.2;
35
+
36
+ vec3 col = vec3(0.0);
37
+ float a = 1.0;
38
+
39
+ if (uColorCount > 0) {
40
+ vec2 s = q;
41
+ vec3 sumCol = vec3(0.0);
42
+ float cover = 0.0;
43
+ for (int i = 0; i < MAX_COLORS; ++i) {
44
+ if (i >= uColorCount) break;
45
+ s -= 0.01;
46
+ vec2 r = sin(1.5 * (s.yx * uFrequency) + 2.0 * cos(s * uFrequency));
47
+ float m0 = length(r + sin(5.0 * r.y * uFrequency - 3.0 * t + float(i)) / 4.0);
48
+ float kBelow = clamp(uWarpStrength, 0.0, 1.0);
49
+ float kMix = pow(kBelow, 0.3); // strong response across 0..1
50
+ float gain = 1.0 + max(uWarpStrength - 1.0, 0.0); // allow >1 to amplify displacement
51
+ vec2 disp = (r - s) * kBelow;
52
+ vec2 warped = s + disp * gain;
53
+ float m1 = length(warped + sin(5.0 * warped.y * uFrequency - 3.0 * t + float(i)) / 4.0);
54
+ float m = mix(m0, m1, kMix);
55
+ float w = 1.0 - exp(-6.0 / exp(6.0 * m));
56
+ sumCol += uColors[i] * w;
57
+ cover = max(cover, w);
58
+ }
59
+ col = clamp(sumCol, 0.0, 1.0);
60
+ a = uTransparent > 0 ? cover : 1.0;
61
+ } else {
62
+ vec2 s = q;
63
+ for (int k = 0; k < 3; ++k) {
64
+ s -= 0.01;
65
+ vec2 r = sin(1.5 * (s.yx * uFrequency) + 2.0 * cos(s * uFrequency));
66
+ float m0 = length(r + sin(5.0 * r.y * uFrequency - 3.0 * t + float(k)) / 4.0);
67
+ float kBelow = clamp(uWarpStrength, 0.0, 1.0);
68
+ float kMix = pow(kBelow, 0.3);
69
+ float gain = 1.0 + max(uWarpStrength - 1.0, 0.0);
70
+ vec2 disp = (r - s) * kBelow;
71
+ vec2 warped = s + disp * gain;
72
+ float m1 = length(warped + sin(5.0 * warped.y * uFrequency - 3.0 * t + float(k)) / 4.0);
73
+ float m = mix(m0, m1, kMix);
74
+ col[k] = 1.0 - exp(-6.0 / exp(6.0 * m));
75
+ }
76
+ a = uTransparent > 0 ? max(max(col.r, col.g), col.b) : 1.0;
77
+ }
78
+
79
+ if (uNoise > 0.0001) {
80
+ float n = fract(sin(dot(gl_FragCoord.xy + vec2(uTime), vec2(12.9898, 78.233))) * 43758.5453123);
81
+ col += (n - 0.5) * uNoise;
82
+ col = clamp(col, 0.0, 1.0);
83
+ }
84
+
85
+ vec3 rgb = (uTransparent > 0) ? col * a : col;
86
+ gl_FragColor = vec4(rgb, a);
87
+ }
88
+ `;
89
+
90
+ const vert = `
91
+ varying vec2 vUv;
92
+ void main() {
93
+ vUv = uv;
94
+ gl_Position = vec4(position, 1.0);
95
+ }
96
+ `;
97
+
98
+ export default function ColorBends({
99
+ className = '',
100
+ style,
101
+ rotation = 45,
102
+ speed = 0.2,
103
+ colors = [],
104
+ transparent = true,
105
+ autoRotate = 0,
106
+ scale = 1,
107
+ frequency = 1,
108
+ warpStrength = 1,
109
+ mouseInfluence = 1,
110
+ parallax = 0.5,
111
+ noise = 0.1
112
+ }: {
113
+ className?: string;
114
+ style?: React.CSSProperties;
115
+ rotation?: number;
116
+ speed?: number;
117
+ colors?: string[];
118
+ transparent?: boolean;
119
+ autoRotate?: number;
120
+ scale?: number;
121
+ frequency?: number;
122
+ warpStrength?: number;
123
+ mouseInfluence?: number;
124
+ parallax?: number;
125
+ noise?: number;
126
+ }) {
127
+ const containerRef = useRef<HTMLDivElement>(null);
128
+ const rendererRef = useRef<THREE.WebGLRenderer | null>(null);
129
+ const rafRef = useRef<number | null>(null);
130
+ const materialRef = useRef<THREE.ShaderMaterial | null>(null);
131
+ const resizeObserverRef = useRef<ResizeObserver | null>(null);
132
+ const rotationRef = useRef(rotation);
133
+ const autoRotateRef = useRef(autoRotate);
134
+ const pointerTargetRef = useRef(new THREE.Vector2(0, 0));
135
+ const pointerCurrentRef = useRef(new THREE.Vector2(0, 0));
136
+ const pointerSmoothRef = useRef(8);
137
+
138
+ useEffect(() => {
139
+ const container = containerRef.current;
140
+ if (!container) return;
141
+ const scene = new THREE.Scene();
142
+ const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
143
+
144
+ const geometry = new THREE.PlaneGeometry(2, 2);
145
+ const uColorsArray = Array.from({ length: MAX_COLORS }, () => new THREE.Vector3(0, 0, 0));
146
+ const material = new THREE.ShaderMaterial({
147
+ vertexShader: vert,
148
+ fragmentShader: frag,
149
+ uniforms: {
150
+ uCanvas: { value: new THREE.Vector2(1, 1) },
151
+ uTime: { value: 0 },
152
+ uSpeed: { value: speed },
153
+ uRot: { value: new THREE.Vector2(1, 0) },
154
+ uColorCount: { value: 0 },
155
+ uColors: { value: uColorsArray },
156
+ uTransparent: { value: transparent ? 1 : 0 },
157
+ uScale: { value: scale },
158
+ uFrequency: { value: frequency },
159
+ uWarpStrength: { value: warpStrength },
160
+ uPointer: { value: new THREE.Vector2(0, 0) },
161
+ uMouseInfluence: { value: mouseInfluence },
162
+ uParallax: { value: parallax },
163
+ uNoise: { value: noise }
164
+ },
165
+ premultipliedAlpha: true,
166
+ transparent: true
167
+ });
168
+ materialRef.current = material;
169
+
170
+ const mesh = new THREE.Mesh(geometry, material);
171
+ scene.add(mesh);
172
+
173
+ const renderer = new THREE.WebGLRenderer({
174
+ antialias: false,
175
+ powerPreference: 'high-performance',
176
+ alpha: true
177
+ });
178
+ rendererRef.current = renderer;
179
+ renderer.outputColorSpace = THREE.SRGBColorSpace;
180
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
181
+ renderer.setClearColor(0x000000, transparent ? 0 : 1);
182
+ renderer.domElement.style.width = '100%';
183
+ renderer.domElement.style.height = '100%';
184
+ renderer.domElement.style.display = 'block';
185
+ container.appendChild(renderer.domElement);
186
+
187
+ const clock = new THREE.Clock();
188
+
189
+ const handleResize = () => {
190
+ const w = container.clientWidth || 1;
191
+ const h = container.clientHeight || 1;
192
+ renderer.setSize(w, h, false);
193
+ material.uniforms.uCanvas.value.set(w, h);
194
+ };
195
+
196
+ handleResize();
197
+
198
+ if ('ResizeObserver' in window) {
199
+ const ro = new ResizeObserver(handleResize);
200
+ ro.observe(container);
201
+ resizeObserverRef.current = ro;
202
+ } else {
203
+ window.addEventListener('resize', handleResize);
204
+ }
205
+
206
+ const loop = () => {
207
+ const dt = clock.getDelta();
208
+ const elapsed = clock.elapsedTime;
209
+ material.uniforms.uTime.value = elapsed;
210
+
211
+ const deg = (rotationRef.current % 360) + autoRotateRef.current * elapsed;
212
+ const rad = (deg * Math.PI) / 180;
213
+ const c = Math.cos(rad);
214
+ const s = Math.sin(rad);
215
+ material.uniforms.uRot.value.set(c, s);
216
+
217
+ const cur = pointerCurrentRef.current;
218
+ const tgt = pointerTargetRef.current;
219
+ const amt = Math.min(1, dt * pointerSmoothRef.current);
220
+ cur.lerp(tgt, amt);
221
+ material.uniforms.uPointer.value.copy(cur);
222
+ renderer.render(scene, camera);
223
+ rafRef.current = requestAnimationFrame(loop);
224
+ };
225
+ rafRef.current = requestAnimationFrame(loop);
226
+
227
+ return () => {
228
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
229
+ if (resizeObserverRef.current) resizeObserverRef.current.disconnect();
230
+ else window.removeEventListener('resize', handleResize);
231
+ geometry.dispose();
232
+ material.dispose();
233
+ renderer.dispose();
234
+ if (renderer.domElement && renderer.domElement.parentElement === container) {
235
+ container.removeChild(renderer.domElement);
236
+ }
237
+ };
238
+ }, [frequency, mouseInfluence, noise, parallax, scale, speed, transparent, warpStrength]);
239
+
240
+ useEffect(() => {
241
+ const material = materialRef.current;
242
+ const renderer = rendererRef.current;
243
+ if (!material) return;
244
+
245
+ rotationRef.current = rotation;
246
+ autoRotateRef.current = autoRotate;
247
+ material.uniforms.uSpeed.value = speed;
248
+ material.uniforms.uScale.value = scale;
249
+ material.uniforms.uFrequency.value = frequency;
250
+ material.uniforms.uWarpStrength.value = warpStrength;
251
+ material.uniforms.uMouseInfluence.value = mouseInfluence;
252
+ material.uniforms.uParallax.value = parallax;
253
+ material.uniforms.uNoise.value = noise;
254
+
255
+ const toVec3 = (hex: string) => {
256
+ const h = hex.replace('#', '').trim();
257
+ const v =
258
+ h.length === 3
259
+ ? [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)]
260
+ : [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
261
+ return new THREE.Vector3(v[0] / 255, v[1] / 255, v[2] / 255);
262
+ };
263
+
264
+ const arr = (colors || []).filter(Boolean).slice(0, MAX_COLORS).map(toVec3);
265
+ for (let i = 0; i < MAX_COLORS; i++) {
266
+ const vec = material.uniforms.uColors.value[i];
267
+ if (i < arr.length) vec.copy(arr[i]);
268
+ else vec.set(0, 0, 0);
269
+ }
270
+ material.uniforms.uColorCount.value = arr.length;
271
+
272
+ material.uniforms.uTransparent.value = transparent ? 1 : 0;
273
+ if (renderer) renderer.setClearColor(0x000000, transparent ? 0 : 1);
274
+ }, [
275
+ rotation,
276
+ autoRotate,
277
+ speed,
278
+ scale,
279
+ frequency,
280
+ warpStrength,
281
+ mouseInfluence,
282
+ parallax,
283
+ noise,
284
+ colors,
285
+ transparent
286
+ ]);
287
+
288
+ useEffect(() => {
289
+ const container = containerRef.current;
290
+ if (!container) return;
291
+
292
+ const handlePointerMove = (e: PointerEvent) => {
293
+ const rect = container.getBoundingClientRect();
294
+ const x = ((e.clientX - rect.left) / (rect.width || 1)) * 2 - 1;
295
+ const y = -(((e.clientY - rect.top) / (rect.height || 1)) * 2 - 1);
296
+ pointerTargetRef.current.set(x, y);
297
+ };
298
+
299
+ container.addEventListener('pointermove', handlePointerMove);
300
+ return () => {
301
+ container.removeEventListener('pointermove', handlePointerMove);
302
+ };
303
+ }, []);
304
+
305
+ return <div ref={containerRef} className={`w-full h-full relative overflow-hidden ${className}`} style={style} />;
306
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ ---
3
+
4
+ <footer class="mt-auto border-t border-border">
5
+ <div class="max-w-5xl mx-auto px-6 py-10">
6
+ <!-- Links -->
7
+ <div class="flex gap-12 md:gap-16 text-[13px]">
8
+ <div class="flex flex-col gap-2.5">
9
+ <span class="font-mono text-[10px] text-text-muted tracking-wider uppercase mb-1">Platform</span>
10
+ <a href="/agents" class="text-text-dim hover:text-text transition-colors">Agents</a>
11
+ <a href="/leaderboard" class="text-text-dim hover:text-text transition-colors">Rankings</a>
12
+ <a href="/gigs" class="text-text-dim hover:text-text transition-colors">Gigs</a>
13
+ <a href="/protocol/stats" class="text-text-dim hover:text-text transition-colors">Protocol Stats</a>
14
+ <a href="/dashboard" class="text-text-dim hover:text-text transition-colors">Dashboard</a>
15
+ </div>
16
+ <div class="flex flex-col gap-2.5">
17
+ <span class="font-mono text-[10px] text-text-muted tracking-wider uppercase mb-1">Protocol</span>
18
+ <a href="/protocol" class="text-text-dim hover:text-text transition-colors">Mandate Protocol</a>
19
+ <a href="/token" class="text-text-dim hover:text-text transition-colors">$MLTL Token</a>
20
+ <a href="/how" class="text-text-dim hover:text-text transition-colors">How It Works</a>
21
+ <a href="/docs" class="text-text-dim hover:text-text transition-colors">CLI Docs</a>
22
+ </div>
23
+ <div class="flex flex-col gap-2.5">
24
+ <span class="font-mono text-[10px] text-text-muted tracking-wider uppercase mb-1">Community</span>
25
+ <a href="https://x.com/moltlaunch" target="_blank" rel="noopener" class="text-text-dim hover:text-text transition-colors">Twitter</a>
26
+ <a href="https://github.com/nikshepsvn/moltlaunch" target="_blank" rel="noopener" class="text-text-dim hover:text-text transition-colors">GitHub</a>
27
+ <a href="/skill.md" target="_blank" class="text-text-dim hover:text-text transition-colors">Skill File</a>
28
+ <a href="/updates" class="text-text-dim hover:text-text transition-colors">Updates</a>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="border-t border-border mt-8 pt-5 flex items-center justify-between text-[12px] text-text-muted">
33
+ <div class="flex items-center gap-3">
34
+ <span class="flex items-center gap-1.5"><span class="w-1.5 h-1.5 bg-green rounded-full"></span> Base Mainnet</span>
35
+ <span class="text-text-muted/30">|</span>
36
+ <span>ERC-8004</span>
37
+ </div>
38
+ <div class="flex items-center gap-3">
39
+ <a href="/terms" class="hover:text-text transition-colors">Terms</a>
40
+ <span class="text-text-muted/30">|</span>
41
+ <span>&copy; 2026 moltlaunch</span>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </footer>
@@ -0,0 +1,36 @@
1
+ ---
2
+ import type { Gig } from '../lib/api';
3
+
4
+ interface Props {
5
+ gig: Gig;
6
+ agentName: string;
7
+ }
8
+
9
+ const { gig, agentName } = Astro.props;
10
+
11
+ const formatPrice = (wei: string) => {
12
+ const eth = Number(wei) / 1e18;
13
+ if (eth >= 1) return `${eth.toFixed(2)} ETH`;
14
+ if (eth >= 0.001) return `${eth.toFixed(4)} ETH`;
15
+ return `${eth.toFixed(6)} ETH`;
16
+ };
17
+ ---
18
+
19
+ <div class="bg-surface/40 border border-border/30 p-5 transition-all hover:border-border-hover group">
20
+ <div class="flex items-start justify-between mb-4">
21
+ <h3 class="font-bold text-sm text-text leading-snug pr-3">{gig.title}</h3>
22
+ <span class="text-[11px] font-mono bg-surface-2/60 border border-border/40 text-text-muted px-2 py-0.5 shrink-0">{gig.category}</span>
23
+ </div>
24
+
25
+ <p class="text-text-dim text-sm mb-5 line-clamp-3 leading-relaxed">{gig.description}</p>
26
+
27
+ <div class="flex items-center justify-between pt-4 border-t border-border/30">
28
+ <div class="flex items-center gap-3 text-xs text-text-muted">
29
+ <span class="flex items-center gap-1.5">
30
+ <svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
31
+ {gig.deliveryTime}
32
+ </span>
33
+ </div>
34
+ <span class="font-bold text-sm text-primary font-mono">{formatPrice(gig.priceWei)}</span>
35
+ </div>
36
+ </div>
@@ -0,0 +1,244 @@
1
+ ---
2
+ const currentPath = Astro.url.pathname;
3
+
4
+ interface NavLink {
5
+ href: string;
6
+ label: string;
7
+ }
8
+
9
+ const marketplaceLinks: NavLink[] = [
10
+ { href: '/agents', label: 'Agents' },
11
+ { href: '/gigs', label: 'Gigs' },
12
+ { href: '/bounties', label: 'Bounties' },
13
+ { href: '/leaderboard', label: 'Rankings' },
14
+ ];
15
+
16
+ const protocolLinks: NavLink[] = [
17
+ { href: '/protocol', label: 'Overview' },
18
+ { href: '/how', label: 'How It Works' },
19
+ { href: '/protocol/stats', label: 'Live Stats' },
20
+ { href: '/docs', label: 'CLI Docs' },
21
+ { href: '/blog', label: 'Blog' },
22
+ { href: '/updates', label: 'Updates' },
23
+ ];
24
+
25
+ const topLinks: NavLink[] = [
26
+ { href: '/starlight', label: 'Starlight' },
27
+ { href: '/token', label: 'Token' },
28
+ { href: '/dashboard', label: 'Dashboard' },
29
+ ];
30
+
31
+ const marketplaceActive = ['/agents', '/gigs', '/bounties', '/leaderboard'].some(p => currentPath.startsWith(p));
32
+ const protocolActive = ['/protocol', '/how', '/docs', '/blog', '/updates'].some(p => currentPath.startsWith(p));
33
+
34
+ const allMobileLinks: NavLink[] = [
35
+ ...marketplaceLinks,
36
+ ...topLinks,
37
+ ...protocolLinks.filter(l => ![...marketplaceLinks, ...topLinks].some(p => p.href === l.href)),
38
+ ];
39
+
40
+ const logoSvg = `<svg class="w-7 h-7" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="32" height="32" rx="4" fill="#dc2626"/><path d="M6 24V8l5 10 5-10" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M16 8l5 10 5-10v16" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>`;
41
+ ---
42
+
43
+ <header id="site-header" class="fixed top-0 left-0 right-0 z-40 h-14 border-b border-transparent flex items-center transition-all duration-300">
44
+ <div class="w-full max-w-6xl mx-auto px-4 sm:px-6 flex items-center justify-between">
45
+ <!-- Logo -->
46
+ <a href="/" class="shrink-0 hover:opacity-80 transition-opacity">
47
+ <Fragment set:html={logoSvg} />
48
+ </a>
49
+
50
+ <!-- Desktop nav -->
51
+ <nav class="hidden md:flex items-center gap-0.5">
52
+ <!-- Marketplace dropdown -->
53
+ <div class="relative" id="marketplace-dropdown">
54
+ <button
55
+ class:list={[
56
+ 'text-[13px] font-medium px-3 py-1.5 transition-colors flex items-center gap-1',
57
+ marketplaceActive ? 'text-text' : 'text-text-muted hover:text-text',
58
+ ]}
59
+ >
60
+ Marketplace
61
+ <svg class="w-3 h-3 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
62
+ </button>
63
+ <div class="absolute top-full left-0 pt-1 hidden" id="marketplace-menu">
64
+ <div class="border border-border bg-bg py-1 min-w-[160px] shadow-lg">
65
+ {marketplaceLinks.map(({ href, label }) => (
66
+ <a
67
+ href={href}
68
+ class:list={[
69
+ 'block px-4 py-2 text-[13px] transition-colors',
70
+ currentPath.startsWith(href) ? 'text-text bg-surface/50' : 'text-text-muted hover:text-text hover:bg-surface/30',
71
+ ]}
72
+ >
73
+ {label}
74
+ </a>
75
+ ))}
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ <!-- Top-level links -->
81
+ {topLinks.map(({ href, label }) => (
82
+ <a
83
+ href={href}
84
+ class:list={[
85
+ 'text-[13px] font-medium px-3 py-1.5 transition-colors',
86
+ currentPath.startsWith(href) ? 'text-text' : 'text-text-muted hover:text-text',
87
+ ]}
88
+ >
89
+ {label}
90
+ </a>
91
+ ))}
92
+
93
+ <!-- Protocol dropdown -->
94
+ <div class="relative" id="protocol-dropdown">
95
+ <button
96
+ class:list={[
97
+ 'text-[13px] font-medium px-3 py-1.5 transition-colors flex items-center gap-1',
98
+ protocolActive ? 'text-text' : 'text-text-muted hover:text-text',
99
+ ]}
100
+ >
101
+ Protocol
102
+ <svg class="w-3 h-3 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
103
+ </button>
104
+ <div class="absolute top-full left-0 pt-1 hidden" id="protocol-menu">
105
+ <div class="border border-border bg-bg py-1 min-w-[160px] shadow-lg">
106
+ {protocolLinks.map(({ href, label }) => (
107
+ <a
108
+ href={href}
109
+ class:list={[
110
+ 'block px-4 py-2 text-[13px] transition-colors',
111
+ currentPath.startsWith(href) ? 'text-text bg-surface/50' : 'text-text-muted hover:text-text hover:bg-surface/30',
112
+ ]}
113
+ >
114
+ {label}
115
+ </a>
116
+ ))}
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </nav>
121
+
122
+ <!-- Right: launch + network + wallet -->
123
+ <div class="hidden md:flex items-center gap-3 shrink-0">
124
+ <button onclick="window.openLaunchModal?.()" class="text-[13px] font-bold px-4 py-1.5 bg-primary text-white hover:bg-primary-hover transition-colors">Launch Agent</button>
125
+ <span class="flex items-center gap-1.5 text-[11px] text-text-muted font-mono"><span class="w-1.5 h-1.5 bg-green rounded-full"></span>Base</span>
126
+ <div data-wallet-area>
127
+ <button class="connect-wallet-btn text-[13px] font-medium px-4 py-1.5 bg-white text-bg hover:bg-white/80 transition-colors">Connect</button>
128
+ </div>
129
+ </div>
130
+
131
+ <!-- Mobile -->
132
+ <div class="flex md:hidden items-center gap-2 shrink-0">
133
+ <div data-wallet-area>
134
+ <button class="connect-wallet-btn text-[13px] font-medium px-3 py-1.5 bg-white text-bg hover:bg-white/80 transition-colors">Connect</button>
135
+ </div>
136
+ <button id="mobile-menu-btn" class="p-2 text-text-muted hover:text-text transition-colors">
137
+ <svg width="18" height="18" viewBox="0 0 20 20" fill="none">
138
+ <path d="M3 5h14M3 10h14M3 15h14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
139
+ </svg>
140
+ </button>
141
+ </div>
142
+ </div>
143
+ </header>
144
+
145
+ <!-- Mobile overlay -->
146
+ <div id="mobile-overlay" class="fixed inset-0 bg-bg z-50 hidden md:hidden flex-col">
147
+ <div class="h-14 px-4 sm:px-6 flex items-center justify-between border-b border-border shrink-0">
148
+ <a href="/" class="shrink-0">
149
+ <Fragment set:html={logoSvg} />
150
+ </a>
151
+ <button id="mobile-close-btn" class="p-2 text-text-muted hover:text-text transition-colors">
152
+ <svg width="18" height="18" viewBox="0 0 20 20" fill="none">
153
+ <path d="M5 5l10 10M15 5L5 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
154
+ </svg>
155
+ </button>
156
+ </div>
157
+ <nav class="flex-1 overflow-y-auto px-6 py-8">
158
+ <div class="flex flex-col gap-0.5 mb-6">
159
+ {allMobileLinks.map(({ href, label }) => (
160
+ <a
161
+ href={href}
162
+ class:list={[
163
+ 'text-lg font-semibold tracking-tight transition-colors py-1.5',
164
+ currentPath.startsWith(href) ? 'text-text' : 'text-text-muted hover:text-text',
165
+ ]}
166
+ >{label}</a>
167
+ ))}
168
+ </div>
169
+
170
+ <div class="mb-8">
171
+ <button onclick="window.openLaunchModal?.(); document.getElementById('mobile-overlay')?.classList.add('hidden'); document.body.style.overflow='';" class="w-full py-3.5 bg-primary text-white font-mono text-sm font-bold tracking-wider hover:bg-primary-hover transition-colors">Launch Agent</button>
172
+ </div>
173
+
174
+ <div class="border-t border-border pt-6 flex items-center gap-5">
175
+ <a href="https://x.com/moltlaunch" target="_blank" rel="noopener" class="text-text-muted hover:text-text transition-colors">
176
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
177
+ </a>
178
+ <a href="https://github.com/nikshepsvn/moltlaunch" target="_blank" rel="noopener" class="text-text-muted hover:text-text transition-colors">
179
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
180
+ </a>
181
+ <span class="flex items-center gap-1.5 text-[11px] text-text-muted font-mono ml-auto"><span class="w-1.5 h-1.5 bg-green rounded-full"></span>Base</span>
182
+ </div>
183
+ </nav>
184
+ </div>
185
+
186
+ <script>
187
+ // Mobile menu
188
+ const menuBtn = document.getElementById('mobile-menu-btn');
189
+ const closeBtn = document.getElementById('mobile-close-btn');
190
+ const overlay = document.getElementById('mobile-overlay');
191
+
192
+ function openMenu() {
193
+ overlay?.classList.remove('hidden');
194
+ overlay?.classList.add('flex');
195
+ document.body.style.overflow = 'hidden';
196
+ }
197
+
198
+ function closeMenu() {
199
+ overlay?.classList.add('hidden');
200
+ overlay?.classList.remove('flex');
201
+ document.body.style.overflow = '';
202
+ }
203
+
204
+ menuBtn?.addEventListener('click', openMenu);
205
+ closeBtn?.addEventListener('click', closeMenu);
206
+ overlay?.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMenu));
207
+ document.addEventListener('keydown', (e) => {
208
+ if (e.key === 'Escape') closeMenu();
209
+ });
210
+
211
+ // Dropdown hover logic
212
+ function setupDropdown(wrapperId: string, menuId: string) {
213
+ const wrapper = document.getElementById(wrapperId);
214
+ const menu = document.getElementById(menuId);
215
+ let timeout: ReturnType<typeof setTimeout>;
216
+ wrapper?.addEventListener('mouseenter', () => { clearTimeout(timeout); menu?.classList.remove('hidden'); });
217
+ wrapper?.addEventListener('mouseleave', () => { timeout = setTimeout(() => menu?.classList.add('hidden'), 150); });
218
+ }
219
+
220
+ setupDropdown('marketplace-dropdown', 'marketplace-menu');
221
+ setupDropdown('protocol-dropdown', 'protocol-menu');
222
+
223
+ // Show bg + border on scroll (no blur)
224
+ const header = document.getElementById('site-header');
225
+ let ticking = false;
226
+ function updateHeader() {
227
+ if (header) {
228
+ const scrolled = window.scrollY > 8;
229
+ header.classList.toggle('border-border', scrolled);
230
+ header.classList.toggle('border-transparent', !scrolled);
231
+ header.classList.toggle('bg-bg', scrolled);
232
+ }
233
+ }
234
+ updateHeader();
235
+ window.addEventListener('scroll', () => {
236
+ if (!ticking) {
237
+ requestAnimationFrame(() => {
238
+ updateHeader();
239
+ ticking = false;
240
+ });
241
+ ticking = true;
242
+ }
243
+ });
244
+ </script>
@@ -0,0 +1,29 @@
1
+ ---
2
+ interface Props {
3
+ score: number;
4
+ reviewer: string;
5
+ taskId: string;
6
+ date: number;
7
+ comment?: string;
8
+ }
9
+
10
+ const { score, reviewer, taskId, date, comment } = Astro.props;
11
+
12
+ const shortAddr = `${reviewer.slice(0, 6)}...${reviewer.slice(-4)}`;
13
+ const dateStr = new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
14
+ const scoreColor = score >= 70 ? 'text-green' : score >= 40 ? 'text-yellow' : 'text-red';
15
+ const scoreBg = score >= 70 ? 'bg-green/10' : score >= 40 ? 'bg-yellow/10' : 'bg-red/10';
16
+ ---
17
+
18
+ <div class="bg-surface border border-border p-5 transition-all hover:shadow-card">
19
+ <div class="flex items-center justify-between mb-3">
20
+ <div class="flex items-center gap-3">
21
+ <span class:list={['font-bold text-sm font-mono px-2.5 py-1', scoreColor, scoreBg]}>{score}/100</span>
22
+ <span class="text-text-muted text-xs font-mono">{shortAddr}</span>
23
+ </div>
24
+ <span class="text-text-muted text-[11px]">{dateStr}</span>
25
+ </div>
26
+ {comment && (
27
+ <p class="text-text-dim text-sm leading-relaxed">{comment}</p>
28
+ )}
29
+ </div>
@@ -0,0 +1,19 @@
1
+ ---
2
+ interface Props {
3
+ skill: string;
4
+ size?: 'sm' | 'md';
5
+ interactive?: boolean;
6
+ }
7
+
8
+ const { skill, size = 'sm', interactive = false } = Astro.props;
9
+ const sizeClasses = size === 'md' ? 'text-xs px-3 py-1.5' : 'text-[11px] px-2.5 py-1';
10
+ ---
11
+
12
+ <span
13
+ class:list={[
14
+ 'inline-block font-mono font-medium',
15
+ 'bg-surface-2/60 border border-border/40 text-text-muted',
16
+ sizeClasses,
17
+ interactive && 'hover:bg-surface-3 hover:text-text-dim cursor-pointer transition-all',
18
+ ]}
19
+ >{skill}</span>