← back to Goodquestion Ai
src/pages/hire.astro
2393 lines
---
// Standalone hire/portfolio page — own layout, own design system
// No imports from BlogLayout or global.css
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hire Agent Abrams — Senior Full Stack Developer</title>
<meta name="description" content="Senior full-stack developer specializing in AI-powered automation, React/Next.js, Node.js, e-commerce platforms, and production systems. Top 3% on Toptal." />
<meta name="author" content="Agent Abrams" />
<!-- Open Graph -->
<meta property="og:title" content="Hire Agent Abrams — Senior Full Stack Developer" />
<meta property="og:description" content="I build production systems that replace entire dev teams. AI-powered automation, full-stack applications, and e-commerce platforms." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://goodquestion.ai/hire" />
<meta property="og:site_name" content="Agent Abrams" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@agentabrams" />
<meta name="twitter:title" content="Hire Agent Abrams — Senior Full Stack Developer" />
<meta name="twitter:description" content="I build production systems that replace entire dev teams. AI-powered automation, full-stack applications, and e-commerce platforms." />
<link rel="canonical" href="https://goodquestion.ai/hire" />
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@700;800;900&display=swap" rel="stylesheet" />
<style>
/* =========================================
RESET & BASE
========================================= */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0A0A0A;
--text: #FFFFFF;
--text-secondary: #AAAAAA;
--brass: #E85D26;
--white: #FFFFFF;
--black: #0A0A0A;
--card-bg: #111111;
--card-border: #1A1A1A;
--display: 'Playfair Display', serif;
--body: 'Inter', 'DM Sans', sans-serif;
}
/* =========================================
SKIP NAV
========================================= */
.skip-nav {
position: absolute;
top: -100%;
left: 16px;
z-index: 10000;
background: var(--brass);
color: var(--white);
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
padding: 12px 24px;
border-radius: 0 0 8px 8px;
text-decoration: none;
transition: top 0.2s;
}
.skip-nav:focus { top: 0; }
html {
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* =========================================
REDUCED MOTION
========================================= */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
.inquiry-form-card,
.inquiry-form-card:hover,
.skill-card:hover,
.project-featured:hover,
.project-card:hover,
.claude-card:hover,
.ecom-card:hover,
.service-card:hover {
transform: none !important;
}
}
body {
font-family: var(--body);
font-weight: 400;
color: var(--text);
background-color: var(--bg);
font-size: 19px;
line-height: 1.75;
position: relative;
overflow-x: hidden;
}
a { text-decoration: none; color: inherit; }
ul, ol { list-style: none; }
img { max-width: 100%; display: block; }
button, input, select, textarea { font-family: inherit; font-size: inherit; }
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
.section-label {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.15em;
color: var(--brass);
margin-bottom: 8px;
text-transform: uppercase;
}
.section-title {
font-family: var(--display);
font-weight: 900;
font-size: 3rem;
color: var(--text);
line-height: 1.1;
margin-bottom: 16px;
}
/* =========================================
NAV
========================================= */
.nav {
position: fixed;
top: 0; left: 0; right: 0;
z-index: 1000;
background: rgba(10, 10, 10, 0.92);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid var(--card-border);
padding: 0 24px;
}
.nav-inner {
max-width: 1200px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
height: 64px;
}
.nav-logo {
display: flex;
align-items: center;
gap: 12px;
}
.nav-logo-circle {
width: 38px;
height: 38px;
border-radius: 50%;
background: var(--brass);
display: flex;
align-items: center;
justify-content: center;
color: var(--white);
font-family: var(--display);
font-weight: 900;
font-size: 1.15rem;
}
.nav-logo-text {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.12em;
color: var(--text);
}
.nav-links {
display: flex;
align-items: center;
gap: 32px;
}
.nav-link {
font-family: var(--body);
font-weight: 500;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--text-secondary);
transition: color 0.3s;
padding: 8px 4px;
min-height: 48px;
display: inline-flex;
align-items: center;
}
.nav-link:hover { color: var(--white); }
.nav-link:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 2px;
border-radius: 4px;
color: var(--white);
}
.nav-cta {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--white);
background: var(--brass);
padding: 12px 24px;
min-height: 48px;
border-radius: 6px;
transition: background 0.3s, transform 0.3s;
border: none;
cursor: pointer;
display: inline-flex;
align-items: center;
}
.nav-cta:hover { background: #D04F1C; transform: translateY(-1px); }
.nav-cta:focus-visible {
outline: 3px solid var(--white);
outline-offset: 2px;
}
/* Mobile hamburger */
.nav-hamburger {
display: none;
flex-direction: column;
gap: 5px;
background: none;
border: none;
cursor: pointer;
padding: 10px;
min-width: 44px;
min-height: 48px;
align-items: center;
justify-content: center;
border-radius: 6px;
}
.nav-hamburger:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 2px;
}
.nav-hamburger span {
display: block;
width: 24px;
height: 2px;
background: var(--text);
transition: transform 0.3s;
}
/* =========================================
HERO
========================================= */
.hero {
padding: 110px 0 60px;
position: relative;
overflow: hidden;
}
.hero .container {
position: relative;
z-index: 1;
}
.hero-inner {
display: grid;
grid-template-columns: 1fr 420px;
gap: 40px;
align-items: center;
}
.hero-label {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.15em;
color: var(--brass);
margin-bottom: 16px;
}
.hero-title {
font-family: var(--display);
font-weight: 900;
font-size: 5.5rem;
line-height: 1.02;
margin-bottom: 28px;
color: var(--text);
}
.hero-title .accent { color: var(--brass); }
.hero-subtitle {
font-family: var(--body);
font-weight: 300;
font-size: 1.15rem;
line-height: 1.7;
color: var(--text-secondary);
max-width: 540px;
margin-bottom: 36px;
}
.hero-ctas {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.btn-solid {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.04em;
padding: 14px 30px;
min-height: 48px;
border-radius: 8px;
border: none;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: var(--brass);
color: var(--white);
}
.btn-primary:hover { background: #D04F1C; transform: translateY(-2px); box-shadow: 0 8px 24px rgba(232,93,38,0.25); }
.btn-solid:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 3px;
}
.btn-outline {
background: transparent;
color: var(--brass);
border: 1.5px solid var(--brass);
padding: 13px 30px;
min-height: 48px;
}
.btn-outline:hover { background: var(--brass); color: var(--white); transform: translateY(-2px); }
/* 3D Canvas Container */
.hero-3d-container {
position: relative;
width: 420px;
height: 380px;
border-radius: 16px;
overflow: hidden;
background: var(--card-bg);
border: 1px solid var(--card-border);
}
#hero-canvas {
width: 100%;
height: 100%;
display: block;
cursor: grab;
}
#hero-canvas:active { cursor: grabbing; }
.hero-3d-label {
position: absolute;
bottom: 8px;
left: 0; right: 0;
text-align: center;
font-family: var(--body);
font-size: 1rem;
color: var(--text-secondary);
letter-spacing: 0.04em;
opacity: 0.5;
}
/* Inline hero stats */
.hero-stats-row {
display: flex;
gap: 32px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--card-border);
}
.hero-stat { display: flex; flex-direction: column; }
.hero-stat-num {
font-family: var(--display);
font-weight: 900;
font-size: 1.8rem;
color: var(--brass);
line-height: 1;
}
.hero-stat-label {
font-family: var(--body);
font-size: 1rem;
color: var(--text-secondary);
letter-spacing: 0.06em;
text-transform: uppercase;
margin-top: 4px;
}
/* =========================================
CORE SKILLS
========================================= */
.skills {
padding: 60px 0;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 40px;
}
.skill-card {
background: var(--card-bg);
border-radius: 14px;
padding: 36px 30px;
transition: transform 0.3s, box-shadow 0.3s;
cursor: default;
position: relative;
overflow: hidden;
border: 1px solid var(--card-border);
}
.skill-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.skill-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
font-size: 1.3rem;
background: rgba(232, 93, 38, 0.1);
color: var(--brass);
}
.skill-title {
font-family: var(--display);
font-weight: 800;
font-size: 1.3rem;
margin-bottom: 10px;
color: var(--text);
}
.skill-techs {
font-family: var(--body);
font-weight: 300;
font-size: 1rem;
line-height: 1.7;
color: var(--text-secondary);
}
.skill-bar {
position: absolute;
bottom: 0;
left: 30px;
right: 30px;
height: 3px;
border-radius: 2px;
background: var(--brass);
}
/* =========================================
PROJECTS
========================================= */
.projects {
padding: 60px 0;
}
.project-featured {
display: grid;
grid-template-columns: 1fr 1fr;
border-radius: 16px;
overflow: hidden;
margin-top: 40px;
min-height: 380px;
transition: transform 0.3s, box-shadow 0.3s;
border: 1px solid var(--card-border);
}
.project-featured:hover {
transform: translateY(-4px);
box-shadow: 0 16px 48px rgba(0,0,0,0.4);
}
.project-featured-content {
background: var(--card-bg);
color: var(--white);
padding: 48px 40px;
display: flex;
flex-direction: column;
justify-content: center;
}
.project-featured-visual {
background: #0D0D0D;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.project-featured-visual svg {
opacity: 0.15;
}
.project-tags {
display: flex;
gap: 8px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.project-tag {
font-family: var(--body);
font-weight: 500;
font-size: 1rem;
letter-spacing: 0.05em;
padding: 5px 12px;
border-radius: 16px;
background: rgba(232, 93, 38, 0.12);
color: var(--brass);
}
.project-title {
font-family: var(--display);
font-weight: 900;
font-size: 2rem;
margin-bottom: 12px;
color: var(--white);
}
.project-desc {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
line-height: 1.7;
color: var(--text-secondary);
margin-bottom: 20px;
}
.project-link {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
color: var(--brass);
display: inline-flex;
align-items: center;
gap: 6px;
transition: gap 0.3s;
}
.project-link:hover { gap: 12px; }
.project-link:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 2px;
border-radius: 2px;
}
.projects-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-top: 24px;
}
.project-card {
background: var(--card-bg);
border-radius: 14px;
padding: 36px 30px;
transition: transform 0.3s, box-shadow 0.3s;
cursor: default;
position: relative;
border: 1px solid var(--card-border);
}
.project-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
/* =========================================
CLAUDE CODE SECTION
========================================= */
.claude-section {
padding: 60px 0;
position: relative;
border-top: 1px solid var(--card-border);
}
.claude-desc {
font-family: var(--body);
font-weight: 400;
font-size: 1.05rem;
line-height: 1.7;
color: var(--text-secondary);
max-width: 640px;
margin-bottom: 40px;
}
.claude-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.claude-card {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 14px;
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
}
.claude-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.claude-card-image {
width: 100%;
height: 200px;
object-fit: cover;
display: block;
}
.claude-card-body {
padding: 24px 26px;
}
.claude-card-title {
font-family: var(--display);
font-weight: 800;
font-size: 1.15rem;
margin-bottom: 10px;
color: var(--white);
}
.claude-card-desc {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
line-height: 1.65;
color: var(--text-secondary);
}
.claude-card-image:hover { opacity: 0.85; cursor: pointer; }
.claude-card-placeholder {
width: 100%;
height: 200px;
background: linear-gradient(135deg, #111111 0%, #181818 100%);
display: flex;
align-items: center;
justify-content: center;
font-family: var(--body);
font-size: 1rem;
font-weight: 600;
color: var(--brass);
letter-spacing: 0.08em;
}
/* =========================================
TOOLS BAR
========================================= */
.tools-bar {
padding: 60px 0;
border-top: 1px solid var(--card-border);
border-bottom: 1px solid var(--card-border);
}
.tools-inner {
display: flex;
justify-content: center;
gap: 64px;
flex-wrap: wrap;
}
.tool-group {
text-align: center;
}
.tool-group-label {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.12em;
color: var(--brass);
margin-bottom: 10px;
}
.tool-group-items {
font-family: var(--body);
font-weight: 300;
font-size: 1rem;
color: var(--text-secondary);
}
/* =========================================
E-COMMERCE SOLUTIONS
========================================= */
.ecom-section {
padding: 60px 0;
position: relative;
border-top: 1px solid var(--card-border);
}
.ecom-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: var(--brass);
}
.ecom-lead {
font-family: var(--body);
font-weight: 300;
font-size: 1.15rem;
line-height: 1.75;
color: var(--text-secondary);
max-width: 680px;
margin-bottom: 40px;
}
.ecom-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-bottom: 40px;
}
.ecom-card {
background: var(--card-bg);
border-radius: 16px;
padding: 36px 30px;
border: 1px solid var(--card-border);
transition: transform 0.3s, box-shadow 0.3s;
position: relative;
}
.ecom-card:hover {
transform: translateY(-6px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.ecom-card-number {
font-family: var(--display);
font-weight: 900;
font-size: 3rem;
color: var(--brass);
position: absolute;
top: 16px;
right: 24px;
line-height: 1;
}
.ecom-card-title {
font-family: var(--display);
font-weight: 800;
font-size: 1.2rem;
color: var(--text);
margin-bottom: 12px;
}
.ecom-card-problem {
font-family: var(--body);
font-style: italic;
font-weight: 400;
font-size: 1rem;
color: var(--brass);
margin-bottom: 14px;
line-height: 1.5;
padding-bottom: 14px;
border-bottom: 1px solid rgba(232, 93, 38, 0.12);
}
.ecom-card-solution {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
line-height: 1.65;
color: var(--text-secondary);
}
.ecom-cta-row {
text-align: center;
}
.ecom-cta-btn {
display: inline-flex;
align-items: center;
padding: 18px 48px;
min-height: 56px;
background: var(--brass);
color: var(--white);
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.04em;
border-radius: 60px;
transition: background 0.3s, transform 0.2s;
}
.ecom-cta-btn:hover {
background: #D04F1C;
transform: translateY(-2px);
}
.ecom-cta-btn:focus-visible {
outline: 3px solid var(--white);
outline-offset: 3px;
}
.ecom-cta-note {
font-family: var(--body);
font-weight: 300;
font-size: 1rem;
color: var(--text-secondary);
margin-top: 14px;
}
/* =========================================
CREDIBILITY BAR
========================================= */
.credibility {
padding: 60px 0;
text-align: center;
border-top: 1px solid var(--card-border);
}
.credibility-label {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.15em;
color: var(--text-secondary);
margin-bottom: 36px;
}
.credibility-row {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
flex-wrap: wrap;
}
.credibility-item {
padding: 0 32px;
text-align: center;
border-right: 1px solid var(--card-border);
}
.credibility-item:last-child { border-right: none; }
.credibility-name {
font-family: var(--display);
font-weight: 800;
font-size: 1.05rem;
color: var(--text);
margin-bottom: 4px;
}
.credibility-sub {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--text-secondary);
}
/* =========================================
SERVICES
========================================= */
.services {
padding: 60px 0;
}
.services-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 40px;
}
.service-card {
background: var(--card-bg);
border-radius: 14px;
padding: 40px 30px;
position: relative;
transition: transform 0.3s, box-shadow 0.3s;
border: 1px solid var(--card-border);
}
.service-card:hover {
transform: translateY(-6px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.service-card.highlighted {
border-color: var(--brass);
}
.services-grid {
align-items: stretch;
}
.service-card {
display: flex;
flex-direction: column;
}
.service-badge {
position: absolute;
top: -12px;
right: 24px;
font-family: var(--body);
font-weight: 700;
font-size: 1rem;
letter-spacing: 0.08em;
padding: 6px 16px;
border-radius: 20px;
background: var(--brass);
color: var(--white);
}
.service-type {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--brass);
margin-bottom: 8px;
}
.service-title {
font-family: var(--display);
font-weight: 900;
font-size: 1.6rem;
margin-bottom: 6px;
color: var(--text);
}
.service-subtitle {
font-family: var(--body);
font-weight: 300;
font-size: 1rem;
color: var(--text-secondary);
margin-bottom: 24px;
}
.service-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.service-list li {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
display: flex;
align-items: flex-start;
gap: 10px;
line-height: 1.5;
color: rgba(255,255,255,0.9);
}
.check-icon {
flex-shrink: 0;
width: 18px;
height: 18px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 2px;
background: rgba(232, 93, 38, 0.12);
color: var(--brass);
}
.check-svg { width: 10px; height: 10px; }
/* =========================================
INQUIRY FORM
========================================= */
.inquiry {
padding: 60px 0;
border-top: 1px solid var(--card-border);
}
.inquiry-inner {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 60px;
align-items: start;
}
.inquiry-info h3 {
font-family: var(--display);
font-weight: 900;
font-size: 2.8rem;
line-height: 1.1;
margin-bottom: 20px;
color: var(--text);
}
.inquiry-info p {
font-family: var(--body);
font-weight: 300;
font-size: 1rem;
color: var(--text-secondary);
line-height: 1.7;
margin-bottom: 32px;
}
.inquiry-detail {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.inquiry-detail-icon {
width: 40px;
height: 40px;
border-radius: 10px;
background: rgba(232, 93, 38, 0.08);
display: flex;
align-items: center;
justify-content: center;
}
.inquiry-detail-icon svg {
width: 18px;
height: 18px;
stroke: var(--brass);
fill: none;
stroke-width: 1.5;
}
.inquiry-detail-label {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--text-secondary);
}
.inquiry-detail-value {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
color: var(--text);
}
.inquiry-form-card {
background: var(--card-bg);
border-radius: 16px;
padding: 40px 36px;
border: 1px solid var(--card-border);
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.08em;
color: var(--text-secondary);
margin-bottom: 8px;
}
.form-input,
.form-select,
.form-textarea {
width: 100%;
padding: 12px 16px;
border: 1.5px solid #333333;
border-radius: 8px;
background: var(--bg);
color: var(--text);
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
line-height: 1.5;
transition: border-color 0.3s, box-shadow 0.3s;
outline: none;
min-height: 48px;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
border-color: var(--brass);
box-shadow: 0 0 0 3px rgba(232, 93, 38, 0.15);
}
.form-input:focus-visible,
.form-select:focus-visible,
.form-textarea:focus-visible {
border-color: var(--brass);
box-shadow: 0 0 0 3px rgba(232, 93, 38, 0.2);
outline: none;
}
.form-textarea { resize: vertical; min-height: 120px; }
.form-select { cursor: pointer; appearance: auto; }
.form-input::placeholder,
.form-textarea::placeholder {
color: #555555;
}
.form-submit {
width: 100%;
padding: 14px 24px;
min-height: 48px;
background: var(--brass);
color: var(--white);
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.04em;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s, transform 0.3s, box-shadow 0.3s;
}
.form-submit:hover {
background: #D04F1C;
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(232, 93, 38, 0.25);
}
.form-submit:focus-visible {
outline: 3px solid var(--white);
outline-offset: 2px;
}
/* =========================================
FOOTER
========================================= */
.footer {
padding: 40px 0 48px;
position: relative;
border-top: 1px solid var(--card-border);
}
.footer-inner {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 32px;
}
.footer-logo {
display: flex;
align-items: center;
gap: 10px;
}
.footer-logo-circle {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--brass);
display: flex;
align-items: center;
justify-content: center;
color: var(--white);
font-family: var(--display);
font-weight: 900;
font-size: 1rem;
}
.footer-logo-text {
font-family: var(--body);
font-weight: 600;
font-size: 1rem;
letter-spacing: 0.1em;
color: var(--text);
}
.footer-links {
display: flex;
gap: 24px;
}
.footer-social-link {
color: var(--text-secondary);
transition: color 0.3s;
display: flex;
align-items: center;
}
.footer-social-link:hover { color: var(--brass); }
.footer-social-link:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 4px;
border-radius: 4px;
}
.footer-social-link svg {
width: 20px;
height: 20px;
fill: currentColor;
}
.nav-logo:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 3px;
border-radius: 4px;
}
.footer-right {
font-family: var(--body);
font-weight: 400;
font-size: 1rem;
color: var(--text-secondary);
}
.footer-right a {
color: var(--brass);
font-weight: 500;
transition: color 0.3s;
}
.footer-right a:hover { color: var(--white); }
/* =========================================
RESPONSIVE
========================================= */
@media (max-width: 1024px) {
.hero-title { font-size: 4rem; }
.hero-inner { grid-template-columns: 1fr 360px; gap: 40px; }
.skills-grid { grid-template-columns: repeat(2, 1fr); }
.claude-grid { grid-template-columns: repeat(2, 1fr); }
.services-grid { grid-template-columns: repeat(2, 1fr); }
.ecom-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
.nav-links { display: none; }
.nav-hamburger { display: flex; }
.hero { padding: 110px 0 60px; }
.hero-inner { grid-template-columns: 1fr; gap: 40px; }
.hero-title { font-size: 3.2rem; }
.hero-subtitle { font-size: 1rem; }
.hero-3d-container {
width: 100%;
max-width: 400px;
height: 300px;
}
.section-title { font-size: 2.2rem; }
.skills-grid { grid-template-columns: 1fr; }
.claude-grid { grid-template-columns: 1fr; }
.services-grid { grid-template-columns: 1fr; }
.ecom-grid { grid-template-columns: 1fr; }
.projects-row { grid-template-columns: 1fr; }
.project-featured { grid-template-columns: 1fr; }
.project-featured-visual { min-height: 200px; }
.inquiry-inner { grid-template-columns: 1fr; gap: 40px; }
.credibility-row { flex-direction: column; gap: 20px; }
.credibility-item { border-right: none; border-bottom: 1px solid var(--card-border); padding: 12px 0; }
.credibility-item:last-child { border-bottom: none; }
.tools-inner { gap: 32px; }
.footer-inner { flex-direction: column; gap: 20px; text-align: center; }
}
@media (max-width: 480px) {
.hero-title { font-size: 2.6rem; }
.hero-ctas { flex-direction: column; }
.hero-ctas .btn-solid, .hero-ctas .btn-outline { width: 100%; justify-content: center; }
.hero-stats-row { gap: 20px; }
.hero-stat-num { font-size: 1.4rem; }
.hero-3d-container { height: 250px; }
}
</style>
</head>
<body>
<!-- SKIP NAVIGATION -->
<a href="#main-content" class="skip-nav">Skip to main content</a>
<!-- NAV -->
<nav class="nav" aria-label="Main navigation">
<div class="nav-inner">
<a href="/hire" class="nav-logo" aria-label="Agent Abrams — return to top">
<div class="nav-logo-circle" aria-hidden="true">A</div>
<span class="nav-logo-text">AGENT ABRAMS</span>
</a>
<div class="nav-links">
<a href="#skills" class="nav-link">SKILLS</a>
<a href="#projects" class="nav-link">PROJECTS</a>
<a href="#catalog" class="nav-link">CATALOG</a>
<a href="#platforms" class="nav-link">PLATFORMS</a>
<a href="#services" class="nav-link">SERVICES</a>
<a href="#inquiry" class="nav-cta">INQUIRE</a>
</div>
<button class="nav-hamburger" aria-label="Toggle navigation" aria-expanded="false" onclick="var l=document.querySelector('.nav-links');l.classList.toggle('mobile-open');this.setAttribute('aria-expanded',l.classList.contains('mobile-open'))">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</button>
</div>
</nav>
<main id="main-content">
<!-- HERO -->
<section class="hero">
<div class="container">
<div class="hero-inner">
<div class="hero-content">
<p class="hero-label">SENIOR FULL STACK DEVELOPER</p>
<h1 class="hero-title">
Agent<br /><span class="accent">Abrams</span>
</h1>
<p class="hero-subtitle">
Solo founder shipping production software fast with AI agents. E-commerce platforms,
AI-generated product catalogs, data explorers, and large-scale directories —
the output of a whole team, run by one operator.
</p>
<div class="hero-ctas">
<a href="#projects" class="btn-solid btn-primary">View Projects</a>
<a href="#inquiry" class="btn-solid btn-outline">Get In Touch</a>
</div>
<div class="hero-stats-row">
<div class="hero-stat"><span class="hero-stat-num">40+</span><span class="hero-stat-label">Years Building</span></div>
<div class="hero-stat"><span class="hero-stat-num">100+</span><span class="hero-stat-label">Projects Shipped</span></div>
<div class="hero-stat"><span class="hero-stat-num">Dozens</span><span class="hero-stat-label">AI Agents</span></div>
</div>
</div>
<div class="hero-3d-container">
<canvas id="hero-canvas" role="img" aria-label="Interactive 3D color wheel visualization"></canvas>
<div class="hero-3d-label">Interactive Color Wheel — Color Matching</div>
</div>
</div>
</div>
</section>
<!-- CORE SKILLS -->
<section class="skills" id="skills">
<div class="container">
<p class="section-label">WHAT I DO</p>
<h2 class="section-title">Core Skills</h2>
<div class="skills-grid">
<!-- 1. Frontend -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
</div>
<h3 class="skill-title">Frontend</h3>
<p class="skill-techs">React, Next.js, Vue, TypeScript, Tailwind CSS, Three.js, WebGL</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
<!-- 2. Backend -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><line x1="4" y1="10" x2="20" y2="10"/><line x1="10" y1="4" x2="10" y2="20"/></svg>
</div>
<h3 class="skill-title">Backend</h3>
<p class="skill-techs">Node.js, Python, PostgreSQL, REST APIs, GraphQL, Redis, AWS</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
<!-- 3. AI / Automation -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
</div>
<h3 class="skill-title">AI / Automation</h3>
<p class="skill-techs">Claude API, LLM pipelines, MCP servers, AI agents, web scraping</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
<!-- 4. E-Commerce -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
</div>
<h3 class="skill-title">E-Commerce</h3>
<p class="skill-techs">Commerce platforms, Liquid, storefront APIs, payment integration, product catalogs</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
<!-- 5. DevOps -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
</div>
<h3 class="skill-title">DevOps</h3>
<p class="skill-techs">PM2, nginx, Docker, CI/CD, Linux server admin, monitoring</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
<!-- 6. Web3 / Crypto -->
<div class="skill-card">
<div class="skill-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1v22"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
</div>
<h3 class="skill-title">Web3 / Crypto</h3>
<p class="skill-techs">DeFi platforms, token systems, blockchain integration, trading bots</p>
<div class="skill-bar" aria-hidden="true"></div>
</div>
</div>
</div>
</section>
<!-- PROJECTS -->
<section class="projects" id="projects">
<div class="container">
<p class="section-label">SELECTED WORK</p>
<h2 class="section-title">Projects</h2>
<!-- Featured: GovArbitrage -->
<div class="project-featured">
<div class="project-featured-content">
<div class="project-tags">
<span class="project-tag">Next.js</span>
<span class="project-tag">Full Stack</span>
<span class="project-tag">Data</span>
</div>
<h3 class="project-title">GovArbitrage</h3>
<p class="project-desc">Aggregates government surplus and seized-asset auctions from dozens of agency sites into one searchable feed, then flags the lots most likely to be underpriced. Tiered subscriptions, Stripe checkout, opportunity scoring.</p>
<a href="https://auctions.agentabrams.com" target="_blank" rel="noopener" class="project-link">auctions.agentabrams.com <span>→</span></a>
</div>
<div class="project-featured-visual" aria-hidden="true">
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" stroke="rgba(232,93,38,0.3)" stroke-width="1" aria-hidden="true">
<rect x="20" y="20" width="80" height="80" rx="4" />
<rect x="30" y="30" width="25" height="25" rx="2" />
<rect x="65" y="30" width="25" height="25" rx="2" />
<rect x="30" y="65" width="25" height="25" rx="2" />
<rect x="65" y="65" width="25" height="25" rx="2" />
</svg>
</div>
</div>
<!-- Row 2 -->
<div class="projects-row">
<div class="project-card">
<div class="project-tags">
<span class="project-tag">Data</span>
<span class="project-tag">PostgreSQL</span>
<span class="project-tag">Open Data</span>
</div>
<h3 class="project-title" style="margin-top: 12px;">National Real Estate Explorer</h3>
<p class="project-desc">A free, nationwide market-data explorer over open parcel, deed, and housing-index datasets — multi-million-row tables kept fast with concurrent indexing.</p>
<a href="https://nationalrealestate.agentabrams.com" target="_blank" rel="noopener" class="project-link">nationalrealestate.agentabrams.com <span>→</span></a>
</div>
<div class="project-card">
<div class="project-tags">
<span class="project-tag">AI</span>
<span class="project-tag">Computer Vision</span>
<span class="project-tag">Commerce</span>
</div>
<h3 class="project-title" style="margin-top: 12px;">AI Wallpaper Studio</h3>
<p class="project-desc">Original AI-generated wallpaper designs with a seamless-tile quality pipeline — edge-scanning, regenerate-until-clean, print-resolution masters, and per-colorway recoloring.</p>
<span class="project-link">Generative design → purchasable product</span>
</div>
</div>
<!-- Row 3 -->
<div class="projects-row">
<div class="project-card">
<div class="project-tags">
<span class="project-tag">Consulting</span>
<span class="project-tag">Full Stack</span>
<span class="project-tag">Growth</span>
</div>
<h3 class="project-title" style="margin-top: 12px;">Client Growth Portals</h3>
<p class="project-desc">A consulting engine that turns a short intake into a full per-client growth command center — competitor research, ad signals, content calendar, costed ideas, and honest first-party analytics.</p>
<a href="https://prestige.agentabrams.com" target="_blank" rel="noopener" class="project-link">prestige.agentabrams.com <span>→</span></a>
</div>
<div class="project-card">
<div class="project-tags">
<span class="project-tag">Next.js</span>
<span class="project-tag">Full Stack</span>
<span class="project-tag">Consumer</span>
</div>
<h3 class="project-title" style="margin-top: 12px;">The Unofficial 90210 Guide</h3>
<p class="project-desc">A full-stack fan guide to a classic TV series — 100+ episode recaps, cast profiles, a 700+ item news feed, and playable mini-games. Built and deployed end-to-end in a single session.</p>
<a href="https://90210.agentabrams.com" target="_blank" rel="noopener" class="project-link">90210.agentabrams.com <span>→</span></a>
</div>
</div>
</div>
</section>
<!-- BUILT WITH CLAUDE CODE -->
<section class="claude-section" id="claude">
<div class="container">
<p class="section-label">BUILT WITH AI</p>
<h2 class="section-title">Claude Code Creations</h2>
<p class="claude-desc">
Production tools built solo with AI agents — applications that automate what used to take
an entire team, from commerce catalogs to autonomous data pipelines. Click any screenshot to enlarge.
</p>
<div class="claude-grid">
<div class="claude-card">
<img src="/images/tools/color-search.jpg" alt="Color Search tool screenshot" class="claude-card-image" loading="lazy" onclick="openLightbox(this)" />
<div class="claude-card-body">
<h3 class="claude-card-title">Color Search</h3>
<p class="claude-card-desc">AI color matching across a large product catalog. Extract hex from any image, find coordinating patterns instantly.</p>
</div>
</div>
<div class="claude-card">
<img src="/images/tools/coordinate-builder.jpg" alt="Coordinate Builder tool screenshot" class="claude-card-image" loading="lazy" onclick="openLightbox(this)" />
<div class="claude-card-body">
<h3 class="claude-card-title">Coordinate Builder</h3>
<p class="claude-card-desc">Drag-and-drop mood boards for design presentations. Combine products, materials, and accents visually.</p>
</div>
</div>
<div class="claude-card">
<img src="/images/tools/paint-visualizer.jpg" alt="Color Visualizer screenshot" class="claude-card-image" loading="lazy" onclick="openLightbox(this)" />
<div class="claude-card-body">
<h3 class="claude-card-title">Color Visualizer</h3>
<p class="claude-card-desc">Color-to-product matcher. A large color library with filtering to find coordinating products instantly.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">ROOM SETTING</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Room Setting Generator</h3>
<p class="claude-card-desc">AI-generated photorealistic room visualizations. Bedroom, living room, office — see products in context before buying.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">360° VIEWER</div>
<div class="claude-card-body">
<h3 class="claude-card-title">360° Spin Viewer</h3>
<p class="claude-card-desc">Interactive WebGL product viewer with smooth rotation. Customers spin products in any direction before purchasing.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">EMAIL → SHOP → SOCIAL</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Email → Shop → Social</h3>
<p class="claude-card-desc">Vendor email arrives → products auto-created in the storefront → social posts generated for Instagram, TikTok, LinkedIn.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">CONTENT SANITIZER</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Content Sanitizer</h3>
<p class="claude-card-desc">200+ regex patterns across 8 security categories. Zero data leaks across 5 publishing channels.</p>
</div>
</div>
<div class="claude-card">
<img src="/images/tools/blog-agent.jpg" alt="Blog Agent dashboard screenshot" class="claude-card-image" loading="lazy" onclick="openLightbox(this)" />
<div class="claude-card-body">
<h3 class="claude-card-title">Agent Orchestrator</h3>
<p class="claude-card-desc">Manages dozens of autonomous Node.js processes on a single VPS. Auto-restart, memory isolation, failure containment.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">AUTO-PUBLISHING</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Auto-Publishing Pipeline</h3>
<p class="claude-card-desc">Generates blog content, sanitizes, publishes to Astro, posts to Twitter, Bluesky, YouTube — every 2 hours.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">VIDEO SANITIZER</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Video Sanitizer</h3>
<p class="claude-card-desc">OCR + OpenCV frame scanning. Detects 214 sensitive patterns, auto-blurs, re-verifies before YouTube upload.</p>
</div>
</div>
<div class="claude-card">
<img src="/images/tools/vendor-command-center.jpg" alt="Vendor Command Center screenshot" class="claude-card-image" loading="lazy" onclick="openLightbox(this)" />
<div class="claude-card-body">
<h3 class="claude-card-title">Vendor Command Center</h3>
<p class="claude-card-desc">Dashboard managing dozens of vendor agents. Health checks, cron schedules, SKU assignment, catalog tracking.</p>
</div>
</div>
<div class="claude-card">
<div class="claude-card-placeholder">SELF-HEALING SCRAPER</div>
<div class="claude-card-body">
<h3 class="claude-card-title">Self-Healing Scraper</h3>
<p class="claude-card-desc">Per-record DB commits, crash recovery, auto-resume. Grew catalogs 10.7x without manual intervention.</p>
</div>
</div>
</div>
</div>
</section>
<!-- LOGIN MODAL -->
<div id="login-modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.92); z-index:9998; align-items:center; justify-content:center;">
<div style="background:#111; border:1px solid #1A1A1A; border-radius:12px; padding:40px; max-width:360px; width:90%;">
<h3 style="font-family:'Playfair Display',serif; font-weight:900; font-size:1.4rem; color:#fff; margin-bottom:8px;">View Tool Screenshots</h3>
<p style="font-family:var(--body); font-size:1rem; color:#AAAAAA; margin-bottom:24px;">Enter credentials to view full-size screenshots.</p>
<input id="login-user" type="text" placeholder="Username" style="width:100%; padding:12px 16px; background:#0A0A0A; border:1px solid #333333; border-radius:6px; color:#fff; font-family:var(--body); font-size:1rem; margin-bottom:12px; outline:none;" />
<input id="login-pass" type="password" placeholder="Password" style="width:100%; padding:12px 16px; background:#0A0A0A; border:1px solid #333333; border-radius:6px; color:#fff; font-family:var(--body); font-size:1rem; margin-bottom:16px; outline:none;" />
<div id="login-error" style="color:#E85D26; font-size:1rem; margin-bottom:12px; display:none;">Invalid credentials</div>
<div style="display:flex; gap:12px;">
<button onclick="doLogin()" style="flex:1; padding:12px; min-height:48px; background:#E85D26; border:none; border-radius:6px; color:#fff; font-family:var(--body); font-weight:600; font-size:1rem; cursor:pointer;">Sign In</button>
<button onclick="closeLogin()" style="flex:1; padding:12px; min-height:48px; background:transparent; border:1px solid #333; border-radius:6px; color:#fff; font-family:var(--body); font-size:1rem; cursor:pointer;">Cancel</button>
</div>
</div>
</div>
<!-- LIGHTBOX -->
<div id="lightbox" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.95); z-index:9999; align-items:center; justify-content:center; flex-direction:column; gap:16px;">
<div style="position:absolute; top:24px; right:32px; font-size:32px; color:#fff; font-family:sans-serif; cursor:pointer; z-index:10000;" onclick="closeLightbox()">×</div>
<div id="lb-tabs" style="display:flex; gap:8px;">
<button id="lb-tab-screenshot" onclick="showLbTab('screenshot')" style="padding:8px 20px; min-height:48px; background:#E85D26; border:none; border-radius:4px; color:#fff; font-family:var(--body); font-weight:600; font-size:1rem; cursor:pointer;">Screenshot</button>
<button id="lb-tab-demo" onclick="showLbTab('demo')" style="padding:8px 20px; min-height:48px; background:#222; border:1px solid #333; border-radius:4px; color:#AAAAAA; font-family:var(--body); font-weight:500; font-size:1rem; cursor:pointer;">Live Demo</button>
</div>
<img id="lightbox-img" style="max-width:90vw; max-height:80vh; border-radius:8px; box-shadow:0 0 60px rgba(0,0,0,0.5);" />
<img id="lightbox-gif" style="max-width:90vw; max-height:80vh; border-radius:8px; box-shadow:0 0 60px rgba(0,0,0,0.5); display:none;" />
<div id="lb-title" style="font-family:'Playfair Display',serif; font-weight:900; font-size:1.2rem; color:#fff; text-align:center;"></div>
</div>
<script is:inline>
var _auth = sessionStorage.getItem('aa_auth') === '1';
var _pendingImg = null;
// Map screenshot filenames to GIF filenames
var _gifMap = {
'color-search.jpg': 'color-search.gif',
'paint-visualizer.jpg': 'paint-visualizer.gif',
'vendor-command-center.jpg': 'vendor-command-center.gif',
'coordinate-builder.jpg': 'coordinate-builder.gif',
'blog-agent.jpg': 'blog-agent.gif'
};
var _currentImgSrc = '';
var _currentGifSrc = '';
var _currentTitle = '';
function openLightbox(img) {
if (!_auth) {
_pendingImg = img;
var m = document.getElementById('login-modal');
m.style.display = 'flex';
document.getElementById('login-user').value = '';
document.getElementById('login-pass').value = '';
document.getElementById('login-error').style.display = 'none';
document.getElementById('login-user').focus();
return;
}
_currentImgSrc = img.src;
var fname = img.src.split('/').pop();
_currentGifSrc = _gifMap[fname] ? img.src.replace(fname, _gifMap[fname]) : '';
_currentTitle = img.alt || '';
document.getElementById('lightbox-img').src = _currentImgSrc;
document.getElementById('lb-title').textContent = _currentTitle;
// Show/hide demo tab based on GIF availability
document.getElementById('lb-tab-demo').style.display = _currentGifSrc ? 'block' : 'none';
showLbTab('screenshot');
document.getElementById('lightbox').style.display = 'flex';
}
function showLbTab(tab) {
var imgEl = document.getElementById('lightbox-img');
var gifEl = document.getElementById('lightbox-gif');
var tabS = document.getElementById('lb-tab-screenshot');
var tabD = document.getElementById('lb-tab-demo');
if (tab === 'demo' && _currentGifSrc) {
imgEl.style.display = 'none';
gifEl.src = _currentGifSrc;
gifEl.style.display = 'block';
tabS.style.background = '#222'; tabS.style.color = '#AAAAAA'; tabS.style.border = '1px solid #333';
tabD.style.background = '#E85D26'; tabD.style.color = '#fff'; tabD.style.border = 'none';
} else {
gifEl.style.display = 'none';
imgEl.style.display = 'block';
tabS.style.background = '#E85D26'; tabS.style.color = '#fff'; tabS.style.border = 'none';
tabD.style.background = '#222'; tabD.style.color = '#AAAAAA'; tabD.style.border = '1px solid #333';
}
}
function doLogin() {
var u = document.getElementById('login-user').value;
var p = document.getElementById('login-pass').value;
if ((u === 'admin' && p === 'ShowMe2024!') || (u === 'Pro' && p === 'AgentAccessPro999')) {
_auth = true;
sessionStorage.setItem('aa_auth', '1');
closeLogin();
if (_pendingImg) { openLightbox(_pendingImg); _pendingImg = null; }
} else {
document.getElementById('login-error').style.display = 'block';
}
}
function closeLogin() {
document.getElementById('login-modal').style.display = 'none';
_pendingImg = null;
}
function closeLightbox() {
document.getElementById('lightbox').style.display = 'none';
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { closeLightbox(); closeLogin(); }
if (e.key === 'Enter' && document.getElementById('login-modal').style.display === 'flex') doLogin();
});
</script>
<!-- TOOLS BAR -->
<section class="tools-bar">
<div class="container">
<div class="tools-inner">
<div class="tool-group">
<p class="tool-group-label">PROJECT MGMT</p>
<p class="tool-group-items">Asana / Trello / Jira</p>
</div>
<div class="tool-group">
<p class="tool-group-label">COMMUNICATION</p>
<p class="tool-group-items">Slack / Teams / Email</p>
</div>
<div class="tool-group">
<p class="tool-group-label">DOCUMENTATION</p>
<p class="tool-group-items">Google Drive / Dropbox</p>
</div>
</div>
</div>
</section>
<!-- E-COMMERCE SOLUTIONS -->
<section class="ecom-section" id="ecommerce">
<div class="container">
<p class="section-label">FOR E-COMMERCE STORE OWNERS</p>
<h2 class="section-title">Drowning in Product Data?</h2>
<p class="ecom-lead">
You have thousands of products, dozens of vendors, and not enough hours. These tools were built
to solve the exact problems that keep e-commerce store owners up at night.
</p>
<div class="ecom-grid">
<!-- 1. Product Data Auditor -->
<div class="ecom-card">
<div class="ecom-card-number">01</div>
<h3 class="ecom-card-title">Product Data Auditor</h3>
<p class="ecom-card-problem">Missing descriptions, broken images, empty metafields — killing your SEO and conversions.</p>
<p class="ecom-card-solution">Auto-scans your entire catalog. Finds SEO gaps, missing images, duplicate products, and empty collections. Generates AI-powered descriptions and fixes metafields in bulk.</p>
</div>
<!-- 2. Vendor Catalog Sync -->
<div class="ecom-card">
<div class="ecom-card-number">02</div>
<h3 class="ecom-card-title">Vendor Catalog Sync</h3>
<p class="ecom-card-problem">Vendor prices change, products get discontinued, your store is always out of date.</p>
<p class="ecom-card-solution">Bi-directional sync engine. Imports vendor catalogs, detects price changes, flags discontinued items, and pushes updates to your storefront — respecting all API rate limits automatically.</p>
</div>
<!-- 3. Discontinued Product Manager -->
<div class="ecom-card">
<div class="ecom-card-number">03</div>
<h3 class="ecom-card-title">Discontinued Product Manager</h3>
<p class="ecom-card-problem">Hundreds of dead products cluttering your store, hurting SEO, confusing customers.</p>
<p class="ecom-card-solution">Monitors vendor sites for 301 redirects and 404s. Auto-archives discontinued products, creates proper redirects, and cleans up orphaned collections. Zero manual work.</p>
</div>
<!-- 4. Image Recovery Agent -->
<div class="ecom-card">
<div class="ecom-card-number">04</div>
<h3 class="ecom-card-title">Image Recovery Agent</h3>
<p class="ecom-card-problem">200+ products with no images sitting live on your store, destroying conversion rates.</p>
<p class="ecom-card-solution">Hunts vendor websites for missing product images, validates formats, auto-uploads to your storefront. Products with no recoverable images get auto-drafted so they stop hurting you.</p>
</div>
<!-- 5. Smart Collection Builder -->
<div class="ecom-card">
<div class="ecom-card-number">05</div>
<h3 class="ecom-card-title">Smart Collection Builder</h3>
<p class="ecom-card-problem">Collections are random — some empty, some with 5 items, some with 200. No strategy.</p>
<p class="ecom-card-solution">AI-powered collection generator with marketing-driven templates. Audits existing collections, removes empties, detects unfocused groupings, and builds curated collections that drive sales.</p>
</div>
<!-- 6. Product Enrichment Pipeline -->
<div class="ecom-card">
<div class="ecom-card-number">06</div>
<h3 class="ecom-card-title">Product Enrichment Pipeline</h3>
<p class="ecom-card-problem">Your product data is shallow — generic descriptions, missing specs, can’t compete with vendors who have rich pages.</p>
<p class="ecom-card-solution">Two-phase enrichment: crawls vendor sites for specs (dimensions, materials, compliance ratings), then generates AI-powered descriptions. Backfills every field your commerce platform supports.</p>
</div>
</div>
<div class="ecom-cta-row">
<a href="#inquiry" class="ecom-cta-btn">Get Your Store Audit →</a>
<p class="ecom-cta-note">Free initial audit — see exactly what’s broken before you spend a dime.</p>
</div>
</div>
</section>
<!-- CATALOG COMMERCE INDUSTRY -->
<section class="ecom-section" id="catalog">
<div class="container">
<p class="section-label">INDUSTRY SOLUTIONS</p>
<h2 class="section-title">Catalog-Heavy Commerce</h2>
<p class="ecom-lead">
Purpose-built tools for brands, wholesalers, and retailers running large, catalog-heavy product lines.
Each one runs autonomously in production — built by one operator with Claude Code, replacing what typically requires an entire dev team.
</p>
<div class="ecom-grid">
<!-- 1. Swatch Spin Viewer -->
<div class="ecom-card">
<div class="ecom-card-number">01</div>
<h3 class="ecom-card-title">360° Swatch Spin Engine</h3>
<p class="ecom-card-problem">Static product images don’t sell textured goods — customers need to see the material up close.</p>
<p class="ecom-card-solution">Generates animated circular swatch GIFs at 2x internal resolution with Lanczos downscaling. Play-button overlay, smooth 180° rotation, auto-uploads to the storefront. One command processes an entire vendor catalog.</p>
</div>
<!-- 2. Vendor Command Center -->
<div class="ecom-card">
<div class="ecom-card-number">02</div>
<h3 class="ecom-card-title">Vendor Command Center</h3>
<p class="ecom-card-problem">Managing 100+ suppliers with spreadsheets and email chains. Nothing syncs, nothing’s current.</p>
<p class="ecom-card-solution">Centralized dashboard managing vendor relationships with real-time catalog health scoring, SKU assignment, catalog normalization, and sync status. Tracks every vendor from initial scrape through storefront deployment.</p>
</div>
<!-- 3. AI Pattern Coordinator -->
<div class="ecom-card">
<div class="ecom-card-number">03</div>
<h3 class="ecom-card-title">AI Pattern Coordinator</h3>
<p class="ecom-card-problem">Creating coordinating collections takes a designer days — matching colors, testing combinations manually.</p>
<p class="ecom-card-solution">Feed it one product image. AI extracts the color palette and generates coordinating patterns and complementary designs. SVG rendering, real-time preview, direct storefront upload as companion products.</p>
</div>
<!-- 4. Executive Dashboard Suite -->
<div class="ecom-card">
<div class="ecom-card-number">04</div>
<h3 class="ecom-card-title">Executive Dashboard Suite</h3>
<p class="ecom-card-problem">No visibility into what your autonomous systems are doing. Reports are manual, meetings are uninformed.</p>
<p class="ecom-card-solution">Five role-based dashboards (CEO, CFO, COO, CTO, VP-Ops) with AI personas using live business data. Real-time agent health, task tracking, meeting agendas, and inter-executive messaging — all automated.</p>
</div>
<!-- 5. Room Visualization Engine -->
<div class="ecom-card">
<div class="ecom-card-number">05</div>
<h3 class="ecom-card-title">Room Visualization Engine</h3>
<p class="ecom-card-problem">Customers can’t imagine how products look in a real space. Returns are high, conversion is low.</p>
<p class="ecom-card-solution">AI-generated photorealistic room settings — bedrooms, living rooms, offices, bathrooms. Multiple viewing distances, proper perspective and pattern scaling. Batch processes thousands of products automatically.</p>
</div>
<!-- 6. Infrastructure Monitor -->
<div class="ecom-card">
<div class="ecom-card-number">06</div>
<h3 class="ecom-card-title">Real-Time System Monitor</h3>
<p class="ecom-card-problem">Agents crash silently, scrapers stall, nobody notices until customers complain about stale data.</p>
<p class="ecom-card-solution">Matrix-style monitoring dashboard tracking every process, database, and API probe in real time. Auto-detects crashes, resource spikes, and degraded services. 30-second health cycles, live event streaming.</p>
</div>
</div>
<div class="ecom-cta-row">
<a href="#inquiry" class="ecom-cta-btn">Bring These to Your Business →</a>
<p class="ecom-cta-note">Available for licensing, customization, or turnkey deployment for catalog-heavy commerce brands.</p>
</div>
</div>
</section>
<!-- CREDIBILITY -->
<section class="credibility" id="platforms">
<div class="container">
<p class="credibility-label">TRUSTED ON</p>
<div class="credibility-row">
<div class="credibility-item">
<p class="credibility-name">TopTal</p>
<p class="credibility-sub">TOP 3% TALENT</p>
</div>
<div class="credibility-item">
<p class="credibility-name">Braintrust</p>
<p class="credibility-sub">VERIFIED EXPERT</p>
</div>
<div class="credibility-item">
<p class="credibility-name">Storetasker</p>
<p class="credibility-sub">E-COMMERCE EXPERT</p>
</div>
<div class="credibility-item">
<p class="credibility-name">GitHub</p>
<p class="credibility-sub">OPEN SOURCE</p>
</div>
<div class="credibility-item">
<p class="credibility-name">Stack Overflow</p>
<p class="credibility-sub">COMMUNITY</p>
</div>
</div>
</div>
</section>
<!-- SERVICES -->
<section class="services" id="services">
<div class="container">
<p class="section-label">HOW I CAN HELP</p>
<h2 class="section-title">Services</h2>
<div class="services-grid">
<!-- Sprint -->
<div class="service-card">
<p class="service-type">SPRINT (1-2 WEEKS)</p>
<h3 class="service-title">Rapid Build</h3>
<p class="service-subtitle">Fast turnaround on focused deliverables</p>
<ul class="service-list">
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Landing pages & marketing sites
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
E-commerce store setup & customization
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
API integrations & webhooks
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Bug fixes & performance tuning
</li>
</ul>
</div>
<!-- Full Build (Popular) -->
<div class="service-card highlighted">
<span class="service-badge">POPULAR</span>
<p class="service-type">FULL BUILD (4-8 WEEKS)</p>
<h3 class="service-title">Complete Product</h3>
<p class="service-subtitle">End-to-end application development</p>
<ul class="service-list">
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Full-stack web applications
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Database architecture & API design
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Production deployment & DevOps
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
3D / WebGL interactive experiences
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
30 days post-launch support
</li>
</ul>
</div>
<!-- AI + Automation -->
<div class="service-card">
<p class="service-type">AI + AUTOMATION (ONGOING)</p>
<h3 class="service-title">AI Systems</h3>
<p class="service-subtitle">Intelligent automation that scales</p>
<ul class="service-list">
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Claude / LLM agent development
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
MCP server architecture
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Web scraping & data pipelines
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
Workflow automation & orchestration
</li>
<li>
<span class="check-icon" aria-hidden="true"><svg class="check-svg" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 6l3 3 5-5"/></svg></span>
AI cost optimization & monitoring
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- INQUIRY FORM -->
<section class="inquiry" id="inquiry">
<div class="container">
<div class="inquiry-inner">
<div class="inquiry-info">
<p class="section-label">GET IN TOUCH</p>
<h3>Let's Build<br />Something</h3>
<p>
Have a project in mind? Whether it's a full-stack application, an AI automation pipeline,
or an e-commerce build — I'd like to hear about it.
</p>
<div class="inquiry-detail">
<div class="inquiry-detail-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div>
<p class="inquiry-detail-label">RESPONSE TIME</p>
<p class="inquiry-detail-value">Within 24 hours</p>
</div>
</div>
<div class="inquiry-detail">
<div class="inquiry-detail-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
</div>
<div>
<p class="inquiry-detail-label">AVAILABILITY</p>
<p class="inquiry-detail-value">Remote worldwide</p>
</div>
</div>
</div>
<div class="inquiry-form-card">
<form id="inquiry-form">
<div class="form-group">
<label class="form-label" for="name">YOUR NAME</label>
<input type="text" id="name" name="name" class="form-input" placeholder="Full name" required />
</div>
<div class="form-group">
<label class="form-label" for="email">EMAIL</label>
<input type="email" id="email" name="email" class="form-input" placeholder="you@company.com" required />
</div>
<div class="form-group">
<label class="form-label" for="project_type">PROJECT TYPE</label>
<select id="project_type" name="project_type" class="form-select" required>
<option value="" disabled selected>Select a project type</option>
<option value="Full Stack App">Full Stack App</option>
<option value="E-Commerce">E-Commerce</option>
<option value="AI Automation">AI Automation</option>
<option value="Consulting">Consulting</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="budget">BUDGET RANGE</label>
<select id="budget" name="budget" class="form-select" required>
<option value="" disabled selected>Select a budget range</option>
<option value="$1k - $5k">$1k - $5k</option>
<option value="$5k - $15k">$5k - $15k</option>
<option value="$15k - $50k">$15k - $50k</option>
<option value="$50k+">$50k+</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="details">PROJECT DETAILS</label>
<textarea id="details" name="details" class="form-textarea" placeholder="Tell me about your project..." rows="4"></textarea>
</div>
<button type="submit" class="form-submit">Send Inquiry</button>
</form>
<script>
document.getElementById('inquiry-form').addEventListener('submit', function(e) {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const type = document.getElementById('project_type').value;
const budget = document.getElementById('budget').value;
const details = document.getElementById('details').value;
const subject = encodeURIComponent('Hire Inquiry: ' + type);
const body = encodeURIComponent(
'Name: ' + name + '\n' +
'Email: ' + email + '\n' +
'Project Type: ' + type + '\n' +
'Budget: ' + budget + '\n\n' +
'Details:\n' + details
);
window.location.href = 'mailto:hello@goodquestion.ai?subject=' + subject + '&body=' + body;
});
</script>
</div>
</div>
</div>
</section>
</main>
<!-- FOOTER -->
<footer class="footer">
<div class="container">
<div class="footer-inner">
<div class="footer-logo">
<div class="footer-logo-circle">A</div>
<span class="footer-logo-text">AGENT ABRAMS</span>
</div>
<div class="footer-links">
<!-- GitHub -->
<a href="https://github.com/AgentAbrams" target="_blank" rel="noopener" class="footer-social-link" aria-label="GitHub">
<svg viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.44 9.8 8.2 11.39.6.11.82-.26.82-.58v-2.03c-3.34.73-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.09-.75.08-.73.08-.73 1.21.08 1.85 1.24 1.85 1.24 1.07 1.84 2.81 1.31 3.5 1 .11-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.13-.3-.54-1.52.12-3.18 0 0 1.01-.32 3.3 1.23a11.5 11.5 0 0 1 6.02 0c2.3-1.55 3.3-1.23 3.3-1.23.66 1.66.25 2.88.12 3.18.77.84 1.24 1.91 1.24 3.22 0 4.61-2.81 5.63-5.48 5.92.43.37.81 1.1.81 2.22v3.29c0 .32.22.7.82.58C20.56 21.8 24 17.3 24 12 24 5.37 18.63 0 12 0z"/></svg>
</a>
<!-- Twitter/X -->
<a href="https://x.com/agentabrams" target="_blank" rel="noopener" class="footer-social-link" aria-label="Twitter">
<svg viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
</a>
<!-- Instagram -->
<a href="https://instagram.com/agentabrams" target="_blank" rel="noopener" class="footer-social-link" aria-label="Instagram">
<svg viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"/></svg>
</a>
<!-- Stack Overflow -->
<a href="https://stackoverflow.com" target="_blank" rel="noopener" class="footer-social-link" aria-label="Stack Overflow">
<svg viewBox="0 0 24 24"><path d="M15.725 0l-1.72 1.277 6.39 8.588 1.716-1.277L15.725 0zm-3.94 3.418l-1.369 1.644 8.225 6.85 1.369-1.644-8.225-6.85zm-3.15 4.465l-.905 1.94 9.702 4.517.904-1.94-9.701-4.517zm-1.85 4.86l-.44 2.093 10.473 2.201.44-2.092-10.473-2.203zM1.89 15.47V24h19.19v-8.53h-2.133v6.397H4.021v-6.396H1.89zm4.265 2.133v2.13h10.66v-2.13H6.154z"/></svg>
</a>
</div>
<div class="footer-right">
<a href="https://goodquestion.ai">goodquestion.ai</a>
</div>
</div>
</div>
</footer>
<!-- Mobile nav toggle styles -->
<style>
.nav-links.mobile-open {
display: flex !important;
flex-direction: column;
position: absolute;
top: 64px;
left: 0;
right: 0;
background: rgba(10, 10, 10, 0.98);
backdrop-filter: blur(12px);
padding: 24px;
gap: 16px;
border-bottom: 1px solid var(--card-border);
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}
@media (min-width: 769px) {
.nav-links.mobile-open {
display: flex !important;
flex-direction: row;
position: static;
background: none;
backdrop-filter: none;
padding: 0;
gap: 32px;
border-bottom: none;
box-shadow: none;
}
}
</style>
<!-- Three.js Color Wheel -->
<script is:inline defer src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script is:inline>
(function() {
const canvas = document.getElementById('hero-canvas');
if (!canvas) return;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, canvas.clientWidth / canvas.clientHeight, 0.1, 100);
camera.position.set(0, 2, 5);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
renderer.setSize(canvas.clientWidth, canvas.clientHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0x000000, 0);
// Lighting
const ambient = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambient);
const directional = new THREE.DirectionalLight(0xfff5e6, 0.8);
directional.position.set(3, 5, 4);
scene.add(directional);
const pointLight = new THREE.PointLight(0xE85D26, 0.4, 10);
pointLight.position.set(-2, 3, 2);
scene.add(pointLight);
// Color palette — tangerine-focused
const palette = [
{ hex: 0xE85D26, name: 'Tangerine' },
{ hex: 0xFF7A45, name: 'Coral' },
{ hex: 0xCC4B1A, name: 'Burnt Orange' },
{ hex: 0x777777, name: 'Steel' },
{ hex: 0x999999, name: 'Silver' },
{ hex: 0xF08C5A, name: 'Apricot' },
{ hex: 0x555555, name: 'Charcoal' },
{ hex: 0xD96B3A, name: 'Amber' },
{ hex: 0xBB4411, name: 'Rust' },
{ hex: 0x888888, name: 'Smoke' },
{ hex: 0xE8794D, name: 'Peach' },
{ hex: 0x666666, name: 'Graphite' },
];
// Build 3D color wheel
const group = new THREE.Group();
const swatchGeom = new THREE.BoxGeometry(0.35, 0.5, 0.08);
palette.forEach((c, i) => {
const angle = (i / palette.length) * Math.PI * 2;
const radius = 1.8;
const mat = new THREE.MeshPhongMaterial({
color: c.hex,
shininess: 60,
specular: 0x333333,
});
const mesh = new THREE.Mesh(swatchGeom, mat);
mesh.position.set(
Math.cos(angle) * radius,
Math.sin(angle * 0.5) * 0.3,
Math.sin(angle) * radius
);
mesh.rotation.y = -angle + Math.PI / 2;
mesh.userData = { baseAngle: angle, name: c.name };
group.add(mesh);
});
// Central hub ring
const ringGeom = new THREE.TorusGeometry(0.6, 0.04, 8, 48);
const ringMat = new THREE.MeshPhongMaterial({ color: 0xE85D26, shininess: 80, transparent: true, opacity: 0.6 });
const ring = new THREE.Mesh(ringGeom, ringMat);
ring.rotation.x = Math.PI / 2;
group.add(ring);
// Inner ring
const ringGeom2 = new THREE.TorusGeometry(0.35, 0.02, 8, 32);
const ring2 = new THREE.Mesh(ringGeom2, ringMat.clone());
ring2.material.opacity = 0.3;
ring2.rotation.x = Math.PI / 2;
ring2.position.y = 0.1;
group.add(ring2);
// Connecting lines
palette.forEach((c, i) => {
const angle = (i / palette.length) * Math.PI * 2;
const points = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(Math.cos(angle) * 1.5, Math.sin(angle * 0.5) * 0.25, Math.sin(angle) * 1.5)
];
const lineGeom = new THREE.BufferGeometry().setFromPoints(points);
const lineMat = new THREE.LineBasicMaterial({ color: 0xE85D26, transparent: true, opacity: 0.15 });
group.add(new THREE.Line(lineGeom, lineMat));
});
// Floating particles
const particleCount = 40;
const particleGeom = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
positions[i * 3] = (Math.random() - 0.5) * 6;
positions[i * 3 + 1] = (Math.random() - 0.5) * 4;
positions[i * 3 + 2] = (Math.random() - 0.5) * 6;
}
particleGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const particleMat = new THREE.PointsMaterial({ color: 0xE85D26, size: 0.03, transparent: true, opacity: 0.4 });
group.add(new THREE.Points(particleGeom, particleMat));
scene.add(group);
// Mouse interaction
let mouseX = 0, mouseY = 0;
let targetRotY = 0, targetRotX = 0;
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
mouseX = ((e.clientX - rect.left) / rect.width) * 2 - 1;
mouseY = ((e.clientY - rect.top) / rect.height) * 2 - 1;
targetRotY = mouseX * 0.5;
targetRotX = mouseY * 0.2;
});
// Touch support
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const t = e.touches[0];
mouseX = ((t.clientX - rect.left) / rect.width) * 2 - 1;
mouseY = ((t.clientY - rect.top) / rect.height) * 2 - 1;
targetRotY = mouseX * 0.5;
targetRotX = mouseY * 0.2;
}, { passive: false });
// Reduced motion check
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
let isCanvasVisible = false;
let animFrameId = null;
// IntersectionObserver — only animate when canvas is visible
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
isCanvasVisible = entry.isIntersecting;
if (isCanvasVisible && !prefersReducedMotion && !animFrameId) {
animate();
}
});
}, { threshold: 0.1 });
observer.observe(canvas);
// Animation loop
function animate() {
if (!isCanvasVisible || prefersReducedMotion) {
animFrameId = null;
return;
}
animFrameId = requestAnimationFrame(animate);
const time = Date.now() * 0.001;
group.rotation.y += 0.003;
group.rotation.y += (targetRotY - group.rotation.y * 0.1) * 0.02;
group.rotation.x += (targetRotX * 0.3 - group.rotation.x) * 0.05;
group.children.forEach((child, i) => {
if (child.isMesh && child.userData.baseAngle !== undefined) {
child.position.y = Math.sin(time + child.userData.baseAngle) * 0.15;
child.rotation.z = Math.sin(time * 0.5 + child.userData.baseAngle) * 0.05;
}
});
ring.scale.setScalar(1 + Math.sin(time * 1.5) * 0.03);
renderer.render(scene, camera);
}
// Render one frame even if reduced motion, so canvas isn't blank
renderer.render(scene, camera);
if (!prefersReducedMotion) animate();
// Resize handler
function onResize() {
const w = canvas.clientWidth, h = canvas.clientHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
window.addEventListener('resize', onResize);
})();
</script>
</body>
</html>