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 */}
+
+
+
+