Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Trace · Digital Footprint RL Environment</title> | |
| <meta name="description" content="Trace — A privacy-centric multi-agent RL environment that builds a Semantic World Model of your digital life. Meta OpenEnv Hackathon 2026."> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> | |
| <style> | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| :root { | |
| --bg: #060810; | |
| --surface: rgba(255,255,255,0.04); | |
| --surface-hover: rgba(255,255,255,0.07); | |
| --border: rgba(255,255,255,0.08); | |
| --border-accent: rgba(139,92,246,0.4); | |
| --text: #f1f5f9; | |
| --muted: #94a3b8; | |
| --purple: #8b5cf6; | |
| --purple-light: #a78bfa; | |
| --indigo: #6366f1; | |
| --green: #10b981; | |
| --amber: #f59e0b; | |
| --red: #ef4444; | |
| --cyan: #06b6d4; | |
| } | |
| html { scroll-behavior: smooth; } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background: var(--bg); | |
| color: var(--text); | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| /* Background */ | |
| .bg-orbs { | |
| position: fixed; inset: 0; pointer-events: none; z-index: 0; | |
| } | |
| .orb { | |
| position: absolute; border-radius: 50%; filter: blur(120px); opacity: 0.15; | |
| } | |
| .orb-1 { width: 600px; height: 600px; background: var(--purple); top: -200px; left: -100px; } | |
| .orb-2 { width: 500px; height: 500px; background: var(--indigo); bottom: -150px; right: -100px; } | |
| .orb-3 { width: 300px; height: 300px; background: var(--cyan); top: 50%; left: 50%; transform: translate(-50%,-50%); } | |
| .wrapper { position: relative; z-index: 1; } | |
| /* Nav */ | |
| nav { | |
| display: flex; justify-content: space-between; align-items: center; | |
| padding: 20px 40px; border-bottom: 1px solid var(--border); | |
| backdrop-filter: blur(20px); | |
| position: sticky; top: 0; z-index: 100; | |
| background: rgba(6,8,16,0.8); | |
| } | |
| .nav-logo { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 18px; } | |
| .nav-logo span { font-size: 22px; } | |
| .nav-badge { | |
| font-size: 11px; padding: 3px 10px; border-radius: 20px; | |
| background: linear-gradient(135deg, var(--purple), var(--indigo)); | |
| font-weight: 600; letter-spacing: 0.5px; | |
| } | |
| .nav-links { display: flex; gap: 8px; } | |
| .nav-link { | |
| padding: 7px 16px; border-radius: 8px; font-size: 13px; font-weight: 500; | |
| color: var(--muted); text-decoration: none; transition: all 0.2s; | |
| border: 1px solid transparent; | |
| } | |
| .nav-link:hover { color: var(--text); background: var(--surface); border-color: var(--border); } | |
| .nav-link.primary { | |
| background: linear-gradient(135deg, var(--purple), var(--indigo)); | |
| color: white; border: none; | |
| } | |
| .nav-link.primary:hover { opacity: 0.9; transform: translateY(-1px); } | |
| /* Hero */ | |
| .hero { | |
| text-align: center; padding: 100px 40px 80px; | |
| max-width: 900px; margin: 0 auto; | |
| } | |
| .hero-tag { | |
| display: inline-flex; align-items: center; gap: 8px; | |
| font-size: 12px; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; | |
| color: var(--purple-light); background: rgba(139,92,246,0.1); | |
| border: 1px solid rgba(139,92,246,0.3); border-radius: 20px; | |
| padding: 6px 16px; margin-bottom: 28px; | |
| } | |
| .hero-tag::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--green); animation: pulse 2s infinite; } | |
| @keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:0.5;transform:scale(0.8)} } | |
| h1 { | |
| font-size: clamp(42px, 7vw, 80px); font-weight: 700; line-height: 1.05; | |
| margin-bottom: 24px; letter-spacing: -2px; | |
| } | |
| .gradient-text { | |
| background: linear-gradient(135deg, #fff 30%, var(--purple-light) 70%, var(--cyan)); | |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; | |
| } | |
| .hero-sub { | |
| font-size: 18px; color: var(--muted); line-height: 1.7; max-width: 620px; | |
| margin: 0 auto 40px; | |
| } | |
| .hero-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } | |
| .btn { | |
| display: inline-flex; align-items: center; gap: 8px; | |
| padding: 13px 28px; border-radius: 10px; font-size: 14px; font-weight: 600; | |
| text-decoration: none; transition: all 0.2s; cursor: pointer; border: none; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--purple), var(--indigo)); | |
| color: white; box-shadow: 0 0 30px rgba(139,92,246,0.3); | |
| } | |
| .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 0 40px rgba(139,92,246,0.5); } | |
| .btn-ghost { | |
| background: var(--surface); color: var(--text); | |
| border: 1px solid var(--border); | |
| } | |
| .btn-ghost:hover { background: var(--surface-hover); border-color: var(--border-accent); } | |
| /* Status bar */ | |
| .status-bar { | |
| display: flex; justify-content: center; gap: 32px; flex-wrap: wrap; | |
| padding: 20px 40px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); | |
| background: var(--surface); | |
| } | |
| .stat-item { text-align: center; } | |
| .stat-value { font-size: 28px; font-weight: 700; font-family: 'JetBrains Mono', monospace; } | |
| .stat-value.green { color: var(--green); } | |
| .stat-value.purple { color: var(--purple-light); } | |
| .stat-value.cyan { color: var(--cyan); } | |
| .stat-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 1px; margin-top: 2px; } | |
| /* Sections */ | |
| .section { padding: 80px 40px; max-width: 1100px; margin: 0 auto; } | |
| .section-header { text-align: center; margin-bottom: 56px; } | |
| .section-tag { | |
| font-size: 11px; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; | |
| color: var(--purple-light); margin-bottom: 12px; | |
| } | |
| .section-title { font-size: 36px; font-weight: 700; letter-spacing: -1px; margin-bottom: 12px; } | |
| .section-sub { color: var(--muted); font-size: 16px; } | |
| /* Feature grid */ | |
| .feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; } | |
| .feature-card { | |
| background: var(--surface); border: 1px solid var(--border); border-radius: 16px; | |
| padding: 28px; transition: all 0.3s; | |
| } | |
| .feature-card:hover { | |
| border-color: var(--border-accent); transform: translateY(-4px); | |
| box-shadow: 0 20px 40px rgba(0,0,0,0.3); | |
| } | |
| .feature-icon { font-size: 32px; margin-bottom: 16px; } | |
| .feature-title { font-size: 17px; font-weight: 600; margin-bottom: 8px; } | |
| .feature-desc { color: var(--muted); font-size: 14px; line-height: 1.7; } | |
| /* Architecture */ | |
| .arch-box { | |
| background: var(--surface); border: 1px solid var(--border); border-radius: 16px; | |
| padding: 32px; font-family: 'JetBrains Mono', monospace; font-size: 13px; | |
| color: var(--muted); line-height: 1.9; overflow-x: auto; | |
| } | |
| .arch-box .hl { color: var(--purple-light); font-weight: 500; } | |
| .arch-box .hl2 { color: var(--cyan); } | |
| .arch-box .hl3 { color: var(--green); } | |
| /* API Explorer */ | |
| .api-grid { display: flex; flex-direction: column; gap: 12px; } | |
| .endpoint { | |
| background: var(--surface); border: 1px solid var(--border); border-radius: 12px; | |
| overflow: hidden; transition: border-color 0.2s; | |
| } | |
| .endpoint:hover { border-color: var(--border-accent); } | |
| .endpoint-header { | |
| display: flex; align-items: center; gap: 14px; padding: 16px 20px; cursor: pointer; | |
| } | |
| .method { | |
| font-size: 11px; font-weight: 700; font-family: 'JetBrains Mono', monospace; | |
| padding: 4px 10px; border-radius: 6px; letter-spacing: 0.5px; min-width: 50px; text-align: center; | |
| } | |
| .method.get { background: rgba(16,185,129,0.15); color: var(--green); } | |
| .method.post { background: rgba(139,92,246,0.15); color: var(--purple-light); } | |
| .method.ws { background: rgba(6,182,212,0.15); color: var(--cyan); } | |
| .endpoint-path { font-family: 'JetBrains Mono', monospace; font-size: 14px; font-weight: 500; } | |
| .endpoint-desc { color: var(--muted); font-size: 13px; margin-left: auto; } | |
| .endpoint-status { | |
| width: 8px; height: 8px; border-radius: 50%; background: var(--green); | |
| box-shadow: 0 0 8px var(--green); flex-shrink: 0; | |
| } | |
| /* Try it */ | |
| .try-box { | |
| background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 28px; | |
| } | |
| .try-label { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 8px; } | |
| .try-url { | |
| font-family: 'JetBrains Mono', monospace; font-size: 14px; | |
| background: rgba(0,0,0,0.4); border: 1px solid var(--border); border-radius: 8px; | |
| padding: 12px 16px; color: var(--purple-light); margin-bottom: 16px; | |
| word-break: break-all; | |
| } | |
| #api-response { | |
| font-family: 'JetBrains Mono', monospace; font-size: 12px; line-height: 1.7; | |
| background: rgba(0,0,0,0.5); border: 1px solid var(--border); border-radius: 8px; | |
| padding: 16px; color: var(--green); min-height: 120px; white-space: pre-wrap; | |
| word-break: break-all; | |
| } | |
| .try-actions { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; } | |
| .try-btn { | |
| padding: 8px 18px; border-radius: 8px; font-size: 13px; font-weight: 600; | |
| cursor: pointer; border: 1px solid var(--border); background: var(--surface); | |
| color: var(--text); transition: all 0.2s; font-family: 'JetBrains Mono', monospace; | |
| } | |
| .try-btn:hover { background: var(--surface-hover); border-color: var(--border-accent); color: var(--purple-light); } | |
| .try-btn.active { background: rgba(139,92,246,0.2); border-color: var(--purple); color: var(--purple-light); } | |
| /* Themes table */ | |
| .themes-table { width: 100%; border-collapse: collapse; } | |
| .themes-table th, .themes-table td { | |
| padding: 14px 18px; text-align: left; border-bottom: 1px solid var(--border); font-size: 14px; | |
| } | |
| .themes-table th { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); } | |
| .themes-table tr:last-child td { border-bottom: none; } | |
| .themes-table tbody tr { transition: background 0.2s; } | |
| .themes-table tbody tr:hover { background: var(--surface); } | |
| .tag-pill { | |
| display: inline-block; font-size: 11px; padding: 2px 10px; border-radius: 20px; | |
| font-weight: 600; | |
| } | |
| .tag-primary { background: rgba(139,92,246,0.15); color: var(--purple-light); } | |
| .tag-secondary { background: rgba(16,185,129,0.1); color: var(--green); } | |
| .tag-tertiary { background: rgba(245,158,11,0.1); color: var(--amber); } | |
| /* Footer */ | |
| footer { | |
| text-align: center; padding: 40px; border-top: 1px solid var(--border); | |
| color: var(--muted); font-size: 13px; | |
| } | |
| footer a { color: var(--purple-light); text-decoration: none; } | |
| @media (max-width: 600px) { | |
| nav { padding: 16px 20px; } | |
| .hero { padding: 60px 20px 50px; } | |
| .nav-links { display: none; } | |
| .section { padding: 50px 20px; } | |
| .status-bar { gap: 20px; padding: 20px; } | |
| .endpoint-desc { display: none; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bg-orbs"> | |
| <div class="orb orb-1"></div> | |
| <div class="orb orb-2"></div> | |
| <div class="orb orb-3"></div> | |
| </div> | |
| <div class="wrapper"> | |
| <!-- Nav --> | |
| <nav> | |
| <div class="nav-logo"> | |
| Trace | |
| <div class="nav-badge">OpenEnv 2026</div> | |
| </div> | |
| <div class="nav-links"> | |
| <a href="#api" class="nav-link">API</a> | |
| <a href="https://github.com/Ayush2904/trace" target="_blank" class="nav-link primary">GitHub ↗</a> | |
| </div> | |
| </nav> | |
| <!-- Hero --> | |
| <div class="hero"> | |
| <div class="hero-tag">Live on HuggingFace Spaces</div> | |
| <h1><span class="gradient-text">Your Digital<br>Footprint</span></h1> | |
| <p class="hero-sub"> | |
| A privacy-centric, multi-agent RL environment that builds a dynamic | |
| <strong>Semantic World Model</strong> of a user's fragmented digital life — without centralizing data. | |
| </p> | |
| <div class="hero-actions"> | |
| <a href="/dashboard" class="btn btn-primary" title="First load fetches live Gmail data — may take 10-20 seconds">View Live Dashboard</a> | |
| <a href="#api" class="btn btn-ghost">Try the API</a> | |
| </div> | |
| </div> | |
| <!-- API Explorer --> | |
| <div class="section" id="api"> | |
| <div class="section-header"> | |
| <div class="section-tag">Live API</div> | |
| <h2 class="section-title">Explore the endpoints</h2> | |
| <p class="section-sub">OpenEnv-compatible REST + WebSocket interface</p> | |
| </div> | |
| <div class="api-grid" style="margin-bottom:32px;"> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method post">POST</div> | |
| <div class="endpoint-path">/reset</div> | |
| <div class="endpoint-desc">Start a new episode</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method post">POST</div> | |
| <div class="endpoint-path">/step</div> | |
| <div class="endpoint-desc">Execute an agent action</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method get">GET</div> | |
| <div class="endpoint-path">/state</div> | |
| <div class="endpoint-desc">Get current environment state</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method get">GET</div> | |
| <div class="endpoint-path">/schema</div> | |
| <div class="endpoint-desc">Action / Observation schemas</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method ws">WS</div> | |
| <div class="endpoint-path">/ws</div> | |
| <div class="endpoint-desc">WebSocket persistent session</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| <div class="endpoint"> | |
| <div class="endpoint-header"> | |
| <div class="method get">GET</div> | |
| <div class="endpoint-path">/health</div> | |
| <div class="endpoint-desc">Health check</div> | |
| <div class="endpoint-status"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Try it live --> | |
| <div class="try-box"> | |
| <div class="try-label">Try it live</div> | |
| <div class="try-url" id="try-url">GET /health</div> | |
| <div class="try-actions"> | |
| <button class="try-btn active" onclick="tryEndpoint('/health','GET',this)">GET /health</button> | |
| <button class="try-btn" onclick="tryEndpoint('/schema','GET',this)">GET /schema</button> | |
| <button class="try-btn" onclick="tryEndpoint('/state','GET',this)">GET /state</button> | |
| </div> | |
| <pre id="api-response">// Click a button above to call the live API...</pre> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Health check function removed as status dot was removed | |
| async function tryEndpoint(path, method, btn) { | |
| document.querySelectorAll('.try-btn').forEach(b => b.classList.remove('active')); | |
| btn.classList.add('active'); | |
| document.getElementById('try-url').textContent = method + ' ' + path; | |
| const out = document.getElementById('api-response'); | |
| out.style.color = '#94a3b8'; | |
| out.textContent = '// Loading...'; | |
| try { | |
| const r = await fetch(path, { method }); | |
| const data = await r.json(); | |
| out.style.color = '#10b981'; | |
| out.textContent = JSON.stringify(data, null, 2); | |
| } catch (e) { | |
| out.style.color = '#ef4444'; | |
| out.textContent = '// Error: ' + e.message; | |
| } | |
| } | |
| // Smooth scroll for nav links | |
| document.querySelectorAll('a[href^="#"]').forEach(a => { | |
| a.addEventListener('click', e => { | |
| e.preventDefault(); | |
| document.querySelector(a.getAttribute('href'))?.scrollIntoView({ behavior: 'smooth' }); | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |