From c78fd44ccd45c385c943d4ada0a1f4c35936de4c Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 14 Jan 2026 00:29:03 -0600 Subject: [PATCH] feat: add procedural cloud background with WebGL shaders Add alternative animated background using multi-pass WebGL rendering with simplex noise, FBM, and ASCII-style quantization. Randomly alternates with existing dots background (50/50 chance). Supports light/dark themes with different contrast and opacity settings. --- ...502adeb64ed912ce2573f046e81f0091417f0.json | 12 + src/cli/seed.rs | 4 +- web/src/lib/components/Clouds.svelte | 896 ++++++++++++++++++ web/src/routes/+layout.svelte | 15 +- 4 files changed, 923 insertions(+), 4 deletions(-) create mode 100644 .sqlx/query-dc2e163d0cbfa64bdc9ea63f8b7502adeb64ed912ce2573f046e81f0091417f0.json create mode 100644 web/src/lib/components/Clouds.svelte diff --git a/.sqlx/query-dc2e163d0cbfa64bdc9ea63f8b7502adeb64ed912ce2573f046e81f0091417f0.json b/.sqlx/query-dc2e163d0cbfa64bdc9ea63f8b7502adeb64ed912ce2573f046e81f0091417f0.json new file mode 100644 index 0000000..5a9bf98 --- /dev/null +++ b/.sqlx/query-dc2e163d0cbfa64bdc9ea63f8b7502adeb64ed912ce2573f046e81f0091417f0.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO tag_cooccurrence (tag_a, tag_b, count)\n SELECT\n LEAST(t1.tag_id, t2.tag_id) as tag_a,\n GREATEST(t1.tag_id, t2.tag_id) as tag_b,\n COUNT(*)::int as count\n FROM project_tags t1\n JOIN project_tags t2 ON t1.project_id = t2.project_id\n WHERE t1.tag_id < t2.tag_id\n GROUP BY tag_a, tag_b\n HAVING COUNT(*) > 0\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "dc2e163d0cbfa64bdc9ea63f8b7502adeb64ed912ce2573f046e81f0091417f0" +} diff --git a/src/cli/seed.rs b/src/cli/seed.rs index 26b3ea0..72a1953 100644 --- a/src/cli/seed.rs +++ b/src/cli/seed.rs @@ -153,7 +153,7 @@ pub async fn run(pool: &PgPool) -> Result<(), Box> { ( "rustdoc-mcp", "rustdoc-mcp", - "MCP server providing AI assistants access to Rust documentation", + "intelligent MCP server providing access to Rust documentation", "A Model Context Protocol (MCP) server that provides AI assistants with direct access to Rust crate documentation. Enables LLMs to query rustdoc-generated documentation, search for types, traits, and functions, and retrieve detailed API information for any published Rust crate. Integrates with Claude, GPT, and other MCP-compatible AI tools to provide accurate, up-to-date Rust API references without hallucination.", "active", Some("Xevion/rustdoc-mcp"), @@ -289,7 +289,7 @@ pub async fn run(pool: &PgPool) -> Result<(), Box> { sqlx::query!( r#" INSERT INTO tag_cooccurrence (tag_a, tag_b, count) - SELECT + SELECT LEAST(t1.tag_id, t2.tag_id) as tag_a, GREATEST(t1.tag_id, t2.tag_id) as tag_b, COUNT(*)::int as count diff --git a/web/src/lib/components/Clouds.svelte b/web/src/lib/components/Clouds.svelte new file mode 100644 index 0000000..b32ef4c --- /dev/null +++ b/web/src/lib/components/Clouds.svelte @@ -0,0 +1,896 @@ + + + + + +
+ +
+ + + {#if !webglFailed} + + {/if} +
diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 9f2a5dc..57831c4 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -9,11 +9,15 @@ import { themeStore } from "$lib/stores/theme.svelte"; import { page } from "$app/stores"; import { onNavigate } from "$app/navigation"; + import Clouds from "$lib/components/Clouds.svelte"; import Dots from "$lib/components/Dots.svelte"; import ThemeToggle from "$lib/components/ThemeToggle.svelte"; let { children, data } = $props(); + // Randomly choose background component on mount (stable, doesn't change after initial load) + let backgroundComponent = $state<"clouds" | "dots" | null>(null); + const defaultMetadata = { title: "Xevion.dev", description: @@ -57,6 +61,9 @@ }); onMount(() => { + // Randomly choose background component (50/50 chance) + backgroundComponent = Math.random() < 0.5 ? "clouds" : "dots"; + // Initialize theme store themeStore.init(); @@ -103,8 +110,12 @@ {#if showGlobalBackground} - - + + {#if backgroundComponent === "clouds"} + + {:else if backgroundComponent === "dots"} + + {/if}