import { useState, useEffect, useRef } from "react"; // --- Mock Data --- const USERS = { scott: { username: "scott", displayName: "Scott Werner", bio: "Writing fiction about near-zero creation costs. Building tools for the things AI helps people make.", avatar: "SW", followers: 312, following: 89 }, maya: { username: "maya", displayName: "Maya Chen", bio: "Data journalist. Making policy arguments you can touch.", avatar: "MC", followers: 1204, following: 156 }, jt: { username: "jt", displayName: "J. Takahashi", bio: "Generative art and weird tools. Previously @stripe.", avatar: "JT", followers: 876, following: 203 }, lina: { username: "lina", displayName: "Lina Park", bio: "Educator. Turning textbooks into playgrounds.", avatar: "LP", followers: 534, following: 67 }, omar: { username: "omar", displayName: "Omar Farouk", bio: "Climate modeling. Every parameter is an argument.", avatar: "OF", followers: 2891, following: 44 }, }; const ARTIFACTS = [ { id: 1, title: "PreTeXt: A New Text Flow Algorithm", user: "maya", description: "An interactive walkthrough of the PreTeXt line-breaking algorithm. Drag text and watch reflow happen in real-time.", tags: ["algorithms", "typography", "explainer"], likes: 847, remixes: 23, remixOf: null, visibility: "public", color: "#1a1a2e", accent: "#e94560", type: "explanation", timeAgo: "2h" }, { id: 2, title: "FFmpeg Clip Exporter", user: "scott", description: "Upload a video, mark in/out points, get the exact ffmpeg commands to export your clips. No server needed.", tags: ["tool", "video", "ffmpeg"], likes: 1203, remixes: 67, remixOf: null, visibility: "public", color: "#0f3460", accent: "#00d2ff", type: "tool", timeAgo: "5h" }, { id: 3, title: "Carbon Budget Explorer", user: "omar", description: "What happens if we hit net zero by 2040? 2050? 2070? Drag the timeline and watch cascading effects across 12 economic sectors.", tags: ["climate", "economics", "simulation"], likes: 3201, remixes: 156, remixOf: null, visibility: "public", color: "#1b4332", accent: "#95d5b2", type: "explanation", timeAgo: "8h" }, { id: 4, title: "Fourier Transform Playground", user: "lina", description: "Draw any wave. Decompose it. Recompose it. Finally understand what a Fourier transform actually does.", tags: ["math", "education", "interactive"], likes: 2156, remixes: 89, remixOf: null, visibility: "public", color: "#2d1b69", accent: "#b8a9e8", type: "explanation", timeAgo: "12h" }, { id: 5, title: "Recursive Subdivision", user: "jt", description: "Generative art piece. Click anywhere to seed. Watch it grow.", tags: ["generative", "art", "creative"], likes: 678, remixes: 34, remixOf: null, visibility: "public", color: "#1a1a1a", accent: "#ff6b6b", type: "creative", timeAgo: "1d" }, { id: 6, title: "Carbon Budget Explorer (EU Variant)", user: "maya", description: "Omar's carbon model adapted for EU-specific policy scenarios and Fit for 55 targets.", tags: ["climate", "EU", "policy"], likes: 890, remixes: 12, remixOf: 3, visibility: "public", color: "#1b4332", accent: "#74c69d", type: "explanation", timeAgo: "1d" }, { id: 7, title: "Series A Model Explorer", user: "scott", description: "Interactive financial model. Shared with investors.", tags: ["finance", "startup"], likes: 0, remixes: 0, remixOf: null, visibility: "unlisted", color: "#16213e", accent: "#4fc3f7", type: "tool", timeAgo: "2d" }, { id: 8, title: "Regex Tester & Explainer", user: "jt", description: "Paste a regex. Get a visual breakdown of what it matches and why. Highlight groups, quantifiers, lookaheads.", tags: ["tool", "regex", "developer"], likes: 1567, remixes: 45, remixOf: null, visibility: "public", color: "#0d1117", accent: "#58a6ff", type: "tool", timeAgo: "2d" }, { id: 9, title: "Housing Affordability Simulator", user: "omar", description: "Set interest rates, zoning policy, and construction costs. Watch 30 years of housing supply and demand play out.", tags: ["economics", "housing", "policy"], likes: 4502, remixes: 201, remixOf: null, visibility: "public", color: "#3d1c02", accent: "#f4a261", type: "explanation", timeAgo: "3d" }, { id: 10, title: "Color Palette from Image", user: "lina", description: "Drop an image. Extract dominant colors. Copy as CSS variables, Tailwind config, or Figma tokens.", tags: ["tool", "design", "color"], likes: 2340, remixes: 78, remixOf: null, visibility: "public", color: "#0c0c1d", accent: "#ffd166", type: "tool", timeAgo: "4d" }, ]; // --- Fake Artifact Renderer --- function FakeArtifact({ artifact, interactive = false }) { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); const w = canvas.width = canvas.offsetWidth * 2; const h = canvas.height = canvas.offsetHeight * 2; ctx.scale(2, 2); const cw = w / 2, ch = h / 2; // Background ctx.fillStyle = artifact.color; ctx.fillRect(0, 0, cw, ch); // Subtle grid ctx.strokeStyle = artifact.accent + "15"; ctx.lineWidth = 0.5; for (let x = 0; x < cw; x += 20) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, ch); ctx.stroke(); } for (let y = 0; y < ch; y += 20) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(cw, y); ctx.stroke(); } // Type-specific decorations if (artifact.type === "explanation") { // Fake slider const sy = ch * 0.65; ctx.fillStyle = artifact.accent + "30"; ctx.fillRect(cw * 0.15, sy, cw * 0.7, 4); ctx.fillStyle = artifact.accent; ctx.beginPath(); ctx.arc(cw * 0.15 + cw * 0.7 * 0.6, sy + 2, 8, 0, Math.PI * 2); ctx.fill(); // Fake chart ctx.strokeStyle = artifact.accent; ctx.lineWidth = 2; ctx.beginPath(); const pts = Array.from({length: 20}, (_, i) => ({ x: cw * 0.15 + (cw * 0.7 / 19) * i, y: ch * 0.2 + Math.sin(i * 0.5) * ch * 0.15 + Math.random() * 10 })); pts.forEach((p, i) => i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y)); ctx.stroke(); // Area fill ctx.lineTo(pts[pts.length-1].x, ch * 0.55); ctx.lineTo(pts[0].x, ch * 0.55); ctx.closePath(); ctx.fillStyle = artifact.accent + "15"; ctx.fill(); } else if (artifact.type === "tool") { // Fake UI elements ctx.fillStyle = artifact.accent + "20"; ctx.fillRect(cw * 0.08, ch * 0.12, cw * 0.84, ch * 0.14); ctx.strokeStyle = artifact.accent + "40"; ctx.lineWidth = 1; ctx.strokeRect(cw * 0.08, ch * 0.12, cw * 0.84, ch * 0.14); // Fake button ctx.fillStyle = artifact.accent; const bw = 80, bh = 28, bx = cw * 0.5 - bw/2, by = ch * 0.75; ctx.beginPath(); ctx.roundRect(bx, by, bw, bh, 6); ctx.fill(); ctx.fillStyle = "#fff"; ctx.font = "11px system-ui"; ctx.textAlign = "center"; ctx.fillText("Run", cw * 0.5, by + 18); // Fake code lines for (let i = 0; i < 5; i++) { ctx.fillStyle = artifact.accent + "25"; const lw = 40 + Math.random() * (cw * 0.5); ctx.fillRect(cw * 0.15, ch * 0.38 + i * 18, lw, 8); } } else { // Creative: generative dots for (let i = 0; i < 60; i++) { const x = Math.random() * cw; const y = Math.random() * ch; const r = 1 + Math.random() * 6; ctx.fillStyle = artifact.accent + Math.floor(20 + Math.random() * 40).toString(16); ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill(); } // Connected lines ctx.strokeStyle = artifact.accent + "20"; ctx.lineWidth = 0.5; for (let i = 0; i < 15; i++) { ctx.beginPath(); ctx.moveTo(Math.random() * cw, Math.random() * ch); ctx.lineTo(Math.random() * cw, Math.random() * ch); ctx.stroke(); } } // Title overlay for thumbnails if (!interactive) { ctx.fillStyle = artifact.color + "cc"; ctx.fillRect(0, ch - 48, cw, 48); ctx.fillStyle = "#fff"; ctx.font = "bold 13px system-ui"; ctx.textAlign = "left"; ctx.fillText(artifact.title.length > 35 ? artifact.title.slice(0, 35) + "…" : artifact.title, 12, ch - 20); } }, [artifact, interactive]); return ; } // --- Icons --- const HeartIcon = ({ filled }) => ( ); const RemixIcon = () => ( ); const ShareIcon = () => ( ); const BackIcon = () => ( ); const PlusIcon = () => ( ); const GridIcon = () => ( ); const LockIcon = () => ( ); const LinkIcon = () => ( ); function formatCount(n) { if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, "") + "k"; return n.toString(); } // --- Components --- function Avatar({ user, size = 32 }) { const colors = { SW: "#6366f1", MC: "#ec4899", JT: "#f97316", LP: "#14b8a6", OF: "#8b5cf6" }; return (
{artifact.description}
Your feed is empty
Follow some makers to see their artifacts here.
{artifact.description}
{user.bio}