diff --git a/src/components/Portfolio.tsx b/src/components/Portfolio.tsx index b192da2..9e8c0fa 100644 --- a/src/components/Portfolio.tsx +++ b/src/components/Portfolio.tsx @@ -151,33 +151,6 @@ const SKILL_GROUPS: Array<{ key: keyof typeof SKILLS; label: string; path: strin { key: "frontend", label: "interface", path: "/stack/interface" }, ]; - -const EXPERIMENTS = { - control: { - label: "A/control", - lede: "I build backend systems that can be understood, operated, and changed after they meet production traffic.", - primary: { label: "View resume", href: "/resume", event: "hero_resume" }, - secondary: { label: "Contact on LinkedIn", href: "https://www.linkedin.com/in/jonathan-peris/", event: "hero_linkedin" }, - tertiary: { label: "See projects", href: "#workbench", event: "hero_projects" }, - }, - clarity: { - label: "B/clarity", - lede: "I design and ship reliable .NET platforms for fintech, cloud, and high-change business domains.", - primary: { label: "Contact me", href: "mailto:jperis.silva@gmail.com", event: "hero_email" }, - secondary: { label: "View resume", href: "/resume", event: "hero_resume" }, - tertiary: { label: "See projects", href: "#workbench", event: "hero_projects" }, - }, - workbench: { - label: "C/workbench", - lede: "Architecture, delivery, and performance workbench for production systems that need clear ownership.", - primary: { label: "Open workbench", href: "#workbench", event: "hero_workbench" }, - secondary: { label: "Contact me", href: "mailto:jperis.silva@gmail.com", event: "hero_email" }, - tertiary: { label: "Resume", href: "/resume", event: "hero_resume" }, - }, -} as const; - -type ExperimentKey = keyof typeof EXPERIMENTS; - function projectLane(project: (typeof FEATURED_PROJECTS)[number]) { const text = `${project.name} ${project.tags.join(" ")}`.toLowerCase(); if (text.includes("rinha") || text.includes("k6") || text.includes("performance")) return "load path"; @@ -189,7 +162,6 @@ function projectLane(project: (typeof FEATURED_PROJECTS)[number]) { export default function Portfolio({ projects }: { projects: GitHubRepo[] }) { const scrollProgress = useScrollProgress(); const featuredSlugs = useMemo(() => new Set(FEATURED_PROJECTS.map((fp) => fp.slug)), []); - const [experiment, setExperiment] = useState("control"); const [termOpen, setTermOpen] = useState(false); const [termInput, setTermInput] = useState(""); @@ -202,23 +174,6 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) { const lastFocusedRef = useRef(null); const konamiRef = useRef([]); - useEffect(() => { - const keys = Object.keys(EXPERIMENTS) as ExperimentKey[]; - const params = new URLSearchParams(window.location.search); - const requested = params.get("ab") as ExperimentKey | null; - const stored = window.localStorage.getItem("jp.heroExperiment") as ExperimentKey | null; - const selected = requested && keys.includes(requested) - ? requested - : stored && keys.includes(stored) - ? stored - : keys[Math.floor(Math.random() * keys.length)]; - - window.localStorage.setItem("jp.heroExperiment", selected); - setExperiment(selected); - document.documentElement.dataset.heroExperiment = selected; - trackEvent("experiment_view", { experiment: "hero_conversion", variant: selected }); - }, []); - useEffect(() => { const K = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"]; const onKey = (e: globalThis.KeyboardEvent) => { @@ -247,12 +202,6 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) { requestAnimationFrame(() => lastFocusedRef.current?.focus()); }, []); - const openTerminal = useCallback(() => { - lastFocusedRef.current = document.activeElement as HTMLElement | null; - setTermOpen(true); - trackEvent("terminal_open", { source: "visible_hint" }); - }, []); - const submit = useCallback(() => { if (!termInput.trim()) return; const result = runCmd(termInput); @@ -298,8 +247,6 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) { [closeTerminal, cmdHist, histIdx, submit], ); - const activeExperiment = EXPERIMENTS[experiment]; - return ( <>
@@ -327,14 +274,11 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) {

Jonathan Peris

Backend architecture / .NET / Azure

- {activeExperiment.lede} + I build backend systems that can be understood, operated, and changed after they meet production traffic.

-

{activeExperiment.label}

- trackEvent("cta_click", { label: activeExperiment.primary.event, variant: experiment })}>{activeExperiment.primary.label} - trackEvent("cta_click", { label: activeExperiment.secondary.event, variant: experiment })}>{activeExperiment.secondary.label} - trackEvent("cta_click", { label: activeExperiment.tertiary.event, variant: experiment })}>{activeExperiment.tertiary.label} - + trackEvent("cta_click", { label: "hero_resume" })}>View resume + trackEvent("cta_click", { label: "hero_linkedin" })}>Contact on LinkedIn
{OPERATING_SIGNALS.map((signal) => ( @@ -442,11 +386,10 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) {

{project.name}

{project.description}

-

{project.proof}

{project.tags.map((tag) => {tag})}
- trackEvent("project_click", { project: project.slug, target: "live" })}>{project.liveLabel} - trackEvent("project_click", { project: project.slug, target: "source" })}>{project.repoLabel} + Source + Live
@@ -484,7 +427,6 @@ export default function Portfolio({ projects }: { projects: GitHubRepo[] }) { {SOCIALS.map((social) => )}

Built as a small systems manual. Hidden shell: ↑↑↓↓←→←→BA

- diff --git a/src/lib/data.ts b/src/lib/data.ts index b5133be..303208d 100644 --- a/src/lib/data.ts +++ b/src/lib/data.ts @@ -20,14 +20,13 @@ export const PROFILE = { }; export const AVAILABILITY = { - short: "Available for remote backend, architecture & consulting work", - full: "Available for remote backend roles, architecture reviews, and select consulting work.", + short: "Open to remote roles + consulting", + full: "Open to remote roles and select backend architecture consulting.", }; export const OPERATING_SIGNALS = [ { label: "12+ yrs", value: "production software" }, { label: ".NET + Azure", value: "primary lane" }, - { label: "Fintech", value: "domain depth" }, { label: "Remote", value: "Brazil to US teams" }, { label: "Systems", value: "architecture + delivery" }, ]; @@ -162,58 +161,43 @@ export type FeaturedProject = { slug: string; name: string; description: string; - proof: string; repoUrl: string; liveUrl: string; - liveLabel: string; - repoLabel: string; lang: string; langColor: string; tags: string[]; }; export const FEATURED_PROJECTS: FeaturedProject[] = [ - { - slug: "cpnucleo", - name: "Cpnucleo", - description: - "A production-shaped .NET 10 reference implementation for systems that need boundaries, tests, and delivery discipline instead of framework theater.", - proof: - "Clean Architecture, DDD, dual REST/gRPC APIs, Docker, DI, and 25+ architecture tests enforced at build time.", - repoUrl: "https://github.com/jonathanperis/cpnucleo", - liveUrl: "https://jonathanperis.github.io/cpnucleo/", - liveLabel: "View docs", - repoLabel: "View source", - lang: "C#", - langColor: "#178600", - tags: ["Clean Architecture", ".NET", "Docker", "DI", "Testing"], - }, { slug: "speedy-bird-lynx", name: "Speedy Bird", description: - "A Flappy Bird clone built with Lynx (ReactLynx + TypeScript), proving a single codebase can render natively across mobile and web surfaces.", - proof: - "Includes accelerating difficulty, medal scoring, web deployment, and a GitHub Actions delivery path for repeatable demos.", + "A Flappy Bird clone built with Lynx (ReactLynx + TypeScript) — ByteDance's cross-platform native UI framework. One codebase renders natively on iOS, Android, and Web. Features accelerating difficulty, medal system, and a full CI/CD pipeline via GitHub Actions.", repoUrl: "https://github.com/jonathanperis/speedy-bird-lynx", liveUrl: "https://jonathanperis.github.io/speedy-bird-lynx/", - liveLabel: "Play demo", - repoLabel: "View source", lang: "TypeScript", langColor: "#3178c6", tags: ["Lynx", "ReactLynx", "TypeScript", "Cross-Platform", "Game Dev"], }, + { + slug: "cpnucleo", + name: "Cpnucleo", + description: + "A full-featured .NET 10 reference implementation — Clean Architecture, DDD, dual REST/gRPC APIs, and 25+ architecture tests enforced at build time. Docs, architecture overview, and API reference available on GitHub Pages.", + repoUrl: "https://github.com/jonathanperis/cpnucleo", + liveUrl: "https://jonathanperis.github.io/cpnucleo/", + lang: "C#", + langColor: "#178600", + tags: ["Clean Architecture", ".NET", "Docker", "DI", "Testing"], + }, { slug: "super-mango-editor", name: "Super Mango Editor", description: - "A classic side-scrolling platformer built from scratch with C and SDL2, then compiled to WebAssembly for instant browser play.", - proof: - "Shows low-level runtime work: sprite animation, collision detection, Emscripten packaging, and retro gameplay constraints.", + "A classic side-scrolling platformer built from scratch with C and SDL2. Compiled to WebAssembly so it runs directly in the browser — no install needed. Features sprite animation, collision detection, and retro-style gameplay.", repoUrl: "https://github.com/jonathanperis/super-mango-editor", liveUrl: "https://jonathanperis.github.io/super-mango-editor/", - liveLabel: "Play in browser", - repoLabel: "View source", lang: "C", langColor: "#555555", tags: ["C", "SDL2", "WebAssembly", "Game Dev", "Emscripten"], @@ -222,13 +206,9 @@ export const FEATURED_PROJECTS: FeaturedProject[] = [ slug: "rinha2-back-end-dotnet", name: "Rinha de Backend 2 — .NET", description: - "A concurrency-focused API built for Rinha de Backend 2024/Q1, where the useful signal is correctness under pressure, not just happy-path latency.", - proof: - "C#, PostgreSQL, and Nginx under strict 1.5 CPU / 550MB RAM constraints with load-oriented architecture choices.", + "My entry for the Rinha de Backend 2024/Q1 challenge — a high-performance concurrency-focused API built in C# with PostgreSQL and Nginx. Designed to handle extreme load under strict resource constraints (1.5 CPU / 550MB RAM).", repoUrl: "https://github.com/jonathanperis/rinha2-back-end-dotnet", liveUrl: "https://jonathanperis.github.io/rinha2-back-end-dotnet/", - liveLabel: "View benchmark notes", - repoLabel: "View source", lang: "C#", langColor: "#178600", tags: ["C#", "PostgreSQL", "Nginx", "High Performance", "Docker"], @@ -237,13 +217,9 @@ export const FEATURED_PROJECTS: FeaturedProject[] = [ slug: "rinha2-back-end-k6", name: "Rinha de Backend 2 — K6 Load Tests", description: - "A Grafana K6 load-testing suite for validating Rinha-style APIs against realistic concurrent traffic instead of hand-wavy performance claims.", - proof: - "Encodes stress scenarios, endpoint validation, and repeatable pressure tests that make backend behavior observable.", + "Load testing suite for the Rinha de Backend 2024/Q1 challenge using Grafana K6. Simulates realistic concurrent traffic patterns to stress-test API endpoints and validate correctness under heavy load.", repoUrl: "https://github.com/jonathanperis/rinha2-back-end-k6", liveUrl: "https://jonathanperis.github.io/rinha2-back-end-k6/", - liveLabel: "Open load tests", - repoLabel: "View source", lang: "JavaScript", langColor: "#f1e05a", tags: ["K6", "Load Testing", "Grafana", "Performance", "Stress Testing"], diff --git a/src/styles/globals.css b/src/styles/globals.css index 0fecfd9..74ccce3 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -23,7 +23,7 @@ --color-rose: oklch(72% 0.17 18); --color-amber: oklch(78% 0.16 68); --font-sans: "DM Sans", -apple-system, system-ui, sans-serif; - --font-display: "DM Serif Display", Georgia, serif; + --font-display: "DM Sans", -apple-system, system-ui, sans-serif; --font-mono: "JetBrains Mono", "Fira Code", monospace; } @@ -163,8 +163,8 @@ body::after { box-shadow: 0 4px 24px rgba(0,0,0,0.3); } .code-block-accent { - border-color: oklch(76% 0.18 151 / 0.28); - box-shadow: inset 0 3px 0 var(--color-violet), 0 0 20px rgba(74, 222, 128, 0.1); + border-left: 3px solid var(--color-violet); + box-shadow: -4px 0 20px rgba(74, 222, 128, 0.1); } .code-block .titlebar { background: var(--color-elevated); @@ -464,19 +464,6 @@ body::after { font-size: clamp(1.04rem, 2vw, 1.22rem); line-height: 1.75; } -.experiment-badge { - display: inline-flex; - margin-top: 1rem; - border: 1px solid oklch(76% 0.18 151 / 0.18); - border-radius: 999px; - background: oklch(94% 0.025 145 / 0.028); - color: var(--color-dim); - font-family: var(--font-mono); - font-size: 0.68rem; - letter-spacing: 0.12em; - padding: 0.35rem 0.55rem; - text-transform: uppercase; -} .hero-actions { display: flex; flex-wrap: wrap; @@ -740,19 +727,8 @@ body::after { letter-spacing: 0.16em; } .workbench-card > p { margin: 0.7rem 0 1rem; } -.workbench-card .project-proof { - border-top: 1px solid oklch(94% 0.025 145 / 0.08); - border-bottom: 1px solid oklch(94% 0.025 145 / 0.08); - margin: 1rem 0; - padding: 0.85rem 0; - color: var(--color-text); - font-family: var(--font-mono); - font-size: 0.76rem; - line-height: 1.65; -} .project-actions { display: flex; - flex-wrap: wrap; gap: 0.7rem; margin-top: 1.1rem; font-family: var(--font-mono); @@ -820,11 +796,6 @@ body::after { .icon-link:hover { color: var(--color-green); } .icon-link svg { width: 1rem; height: 1rem; } .icon-link.compact span { display: none; } -.footer-terminal { - color: var(--color-green); - cursor: pointer; -} -.footer-terminal:hover { color: var(--color-violet-light); } .terminal-dialog { width: min(720px, 100%);