diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 8422bc7..9098381 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -24,7 +24,7 @@ export default function Home() {
-

+

Digital Craftsmanship

diff --git a/apps/web/src/components/portfolio/bento-grid.tsx b/apps/web/src/components/portfolio/bento-grid.tsx index d12f7e4..b3e01ce 100644 --- a/apps/web/src/components/portfolio/bento-grid.tsx +++ b/apps/web/src/components/portfolio/bento-grid.tsx @@ -5,17 +5,17 @@ export const PortfolioGrid = () => { return (

{/* Hero Project: r/CryptoCurrency */} - +

r/CryptoCurrency

Governance dashboard for 10M+ members. Real-time DAO metrics.

{/* Placeholder image since we don't have the assets yet */} -
+
{/* Secondary: Occupy Wallets */} - +

Occupy Wallets

High-fidelity gallery for fiscal graffiti.

@@ -23,7 +23,7 @@ export const PortfolioGrid = () => { {/* Tertiary: Monerogue & Wowne.ro (Grouped) */} - +

Privacy Labs

    @@ -34,7 +34,7 @@ export const PortfolioGrid = () => { {/* Quaternary: MoonPlace */} - +

    MoonPlace

    Collaborative pixel canvas engine.

    diff --git a/packages/ui/src/procedural/nebula-field.tsx b/packages/ui/src/procedural/nebula-field.tsx index b6ae607..3d0f92f 100644 --- a/packages/ui/src/procedural/nebula-field.tsx +++ b/packages/ui/src/procedural/nebula-field.tsx @@ -3,6 +3,7 @@ import { motion } from "framer-motion"; import { useEffect, useState } from "react"; import { cn } from "../lib/utils"; +import { Monitor } from "lucide-react"; interface NebulaProps { className?: string; @@ -10,51 +11,88 @@ interface NebulaProps { themeMode?: 'light' | 'dark'; // customized prop } -export const NebulaField = ({ className, density = 15, themeMode = 'dark' }: NebulaProps) => { +export const NebulaField = ({ className, density = 20, themeMode = 'dark' }: NebulaProps) => { const [paths, setPaths] = useState([]); + const [mounted, setMounted] = useState(false); + + // Configuration for convergence point (percent of container) + const targetX = 25; // moved right + const targetY = 20; // moved up - // Procedural generation: Create organic bezier curves useEffect(() => { + setMounted(true); const newPaths = Array.from({ length: density }).map(() => { - // Random control points - const startX = Math.random() * 100; - const startY = Math.random() * 100; - const cp1X = startX + (Math.random() - 0.5) * 50; - const cp1Y = startY + (Math.random() - 0.5) * 50; - const endX = Math.random() * 100; - const endY = Math.random() * 100; + // Determine random edge start point + const edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left + let startX = 50, startY = 50; - return `M ${startX} ${startY} Q ${cp1X} ${cp1Y} ${endX} ${endY}`; + // Push start point well outside viewbox to ensure full coverage + switch(edge) { + case 0: startX = Math.random() * 100; startY = -20; break; // Top + case 1: startX = 120; startY = Math.random() * 100; break; // Right + case 2: startX = Math.random() * 100; startY = 120; break; // Bottom + case 3: startX = -20; startY = Math.random() * 100; break; // Left + } + + // End at target point with small variance + const endX = targetX + (Math.random() - 0.5) * 5; + const endY = targetY + (Math.random() - 0.5) * 5; + + // Control point for curve + const cpX = (startX + endX) / 2 + (Math.random() - 0.5) * 50; + const cpY = (startY + endY) / 2 + (Math.random() - 0.5) * 50; + + return `M ${startX} ${startY} Q ${cpX} ${cpY} ${endX} ${endY}`; }); setPaths(newPaths); - }, [density]); + }, [density, targetX, targetY]); + + if (!mounted) return null; return (
    + + {/* "Computer" Icon positioned via inline styles to match physics target exactly */} +
    + +
    + {paths.map((d, i) => ( ))}