Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PhoneGPU — Windsurf Bridge</title> | |
| <style> | |
| :root { | |
| --bg: #030305; | |
| --bg-card: rgba(255, 255, 255, 0.02); | |
| --border: rgba(255, 255, 255, 0.06); | |
| --text: #f0f0f5; | |
| --text-muted: #6b6b78; | |
| --cyan: #00f0ff; | |
| --cyan-dim: rgba(0, 240, 255, 0.08); | |
| --violet: #a78bfa; | |
| --violet-dim: rgba(167, 139, 250, 0.08); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Inter', sans-serif; | |
| background: var(--bg); | |
| color: var(--text); | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| canvas#bg { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 0; | |
| } | |
| .content { | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .hero { | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| text-align: center; | |
| padding: 40px 20px; | |
| } | |
| .hero h1 { | |
| font-size: clamp(40px, 8vw, 96px); | |
| font-weight: 800; | |
| letter-spacing: -3px; | |
| line-height: 1.05; | |
| background: linear-gradient(135deg, #fff 30%, var(--cyan) 70%); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 16px; | |
| } | |
| .hero .subtitle { | |
| font-size: clamp(16px, 2vw, 22px); | |
| color: var(--text-muted); | |
| max-width: 560px; | |
| line-height: 1.5; | |
| margin-bottom: 40px; | |
| } | |
| .hero .tagline { | |
| font-family: 'SF Mono', 'JetBrains Mono', monospace; | |
| font-size: 12px; | |
| color: var(--cyan); | |
| letter-spacing: 4px; | |
| text-transform: uppercase; | |
| margin-bottom: 24px; | |
| opacity: 0.8; | |
| } | |
| .cta-row { | |
| display: flex; | |
| gap: 16px; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| } | |
| .btn { | |
| padding: 14px 32px; | |
| border-radius: 12px; | |
| font-size: 14px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| border: none; | |
| transition: all 0.3s; | |
| text-decoration: none; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--cyan), #00c8d6); | |
| color: #000; | |
| box-shadow: 0 0 40px -10px rgba(0, 240, 255, 0.4); | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 0 60px -10px rgba(0, 240, 255, 0.6); | |
| } | |
| .btn-ghost { | |
| background: transparent; | |
| color: var(--text); | |
| border: 1px solid var(--border); | |
| } | |
| .btn-ghost:hover { | |
| border-color: rgba(255, 255, 255, 0.2); | |
| background: rgba(255, 255, 255, 0.03); | |
| } | |
| .section { | |
| padding: 120px 24px; | |
| max-width: 1100px; | |
| margin: 0 auto; | |
| } | |
| .section h2 { | |
| font-size: clamp(28px, 4vw, 48px); | |
| font-weight: 700; | |
| letter-spacing: -1px; | |
| margin-bottom: 16px; | |
| } | |
| .section p.lead { | |
| color: var(--text-muted); | |
| font-size: 18px; | |
| line-height: 1.6; | |
| max-width: 640px; | |
| } | |
| .feature-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); | |
| gap: 20px; | |
| margin-top: 60px; | |
| } | |
| .feature-card { | |
| background: var(--bg-card); | |
| border: 1px solid var(--border); | |
| border-radius: 20px; | |
| padding: 32px; | |
| transition: all 0.3s; | |
| } | |
| .feature-card:hover { | |
| border-color: rgba(0, 240, 255, 0.2); | |
| background: rgba(0, 240, 255, 0.02); | |
| transform: translateY(-4px); | |
| } | |
| .feature-card .icon { | |
| width: 44px; | |
| height: 44px; | |
| border-radius: 12px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 20px; | |
| margin-bottom: 20px; | |
| } | |
| .feature-card h3 { | |
| font-size: 18px; | |
| margin-bottom: 8px; | |
| } | |
| .feature-card p { | |
| font-size: 14px; | |
| color: var(--text-muted); | |
| line-height: 1.5; | |
| } | |
| .bridge-demo { | |
| background: var(--bg-card); | |
| border: 1px solid var(--border); | |
| border-radius: 24px; | |
| padding: 40px; | |
| margin-top: 60px; | |
| } | |
| .bridge-visual { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 40px; | |
| padding: 40px 0; | |
| flex-wrap: wrap; | |
| } | |
| .bridge-node { | |
| width: 120px; | |
| height: 120px; | |
| border-radius: 24px; | |
| border: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| font-size: 13px; | |
| position: relative; | |
| } | |
| .bridge-node.active { | |
| border-color: var(--cyan); | |
| box-shadow: 0 0 40px -15px var(--cyan-dim); | |
| } | |
| .bridge-node .node-label { | |
| color: var(--text-muted); | |
| font-size: 11px; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| .bridge-connector { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 4px; | |
| } | |
| .bridge-connector .line { | |
| width: 80px; | |
| height: 2px; | |
| background: linear-gradient(90deg, var(--cyan), var(--violet)); | |
| position: relative; | |
| } | |
| .bridge-connector .line::after { | |
| content: ''; | |
| position: absolute; | |
| right: 0; | |
| top: -3px; | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--cyan); | |
| animation: pulse 1.5s ease-in-out infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, | |
| 100% { | |
| opacity: 1; | |
| transform: scale(1); | |
| } | |
| 50% { | |
| opacity: 0.4; | |
| transform: scale(1.5); | |
| } | |
| } | |
| .nav { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| z-index: 100; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 20px 32px; | |
| backdrop-filter: blur(20px); | |
| background: rgba(3, 3, 5, 0.6); | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .nav .logo { | |
| font-weight: 700; | |
| font-size: 16px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .nav .links { | |
| display: flex; | |
| gap: 24px; | |
| } | |
| .nav a { | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| font-size: 13px; | |
| transition: color 0.2s; | |
| } | |
| .nav a:hover { | |
| color: var(--text); | |
| } | |
| footer { | |
| padding: 60px 24px; | |
| text-align: center; | |
| color: var(--text-muted); | |
| font-size: 13px; | |
| border-top: 1px solid var(--border); | |
| } | |
| @media (max-width: 640px) { | |
| .nav .links { | |
| display: none; | |
| } | |
| .bridge-visual { | |
| flex-direction: column; | |
| } | |
| .bridge-connector .line { | |
| width: 2px; | |
| height: 60px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="bg"></canvas> | |
| <nav class="nav"> | |
| <div class="logo"> | |
| <span style="color:var(--cyan)">◈</span> PhoneGPU | |
| </div> | |
| <div class="links"> | |
| <a href="#bridge">Windsurf Bridge</a> | |
| <a href="#mesh">Device Mesh</a> | |
| <a href="/dashboard">Dashboard</a> | |
| </div> | |
| <a href="/dashboard" class="btn btn-primary" style="padding:8px 18px;font-size:12px">Launch</a> | |
| </nav> | |
| <div class="content"> | |
| <section class="hero"> | |
| <div class="tagline">Edge Compute Infrastructure</div> | |
| <h1>Your hardware.<br>Global API.</h1> | |
| <p class="subtitle"> | |
| PhoneGPU turns your iPhone and MacBook into a private, attested inference cluster. | |
| A Hugging Face Space becomes the control plane. Your devices become the neural engine. | |
| </p> | |
| <div class="cta-row"> | |
| <a href="/dashboard" class="btn btn-primary">Open Dashboard</a> | |
| <a href="#bridge" class="btn btn-ghost">How it works</a> | |
| </div> | |
| </section> | |
| <section class="section" id="bridge"> | |
| <h2 | |
| style="background:linear-gradient(135deg,#fff,var(--cyan));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent"> | |
| Windsurf Bridge</h2> | |
| <p class="lead"> | |
| A zero-config peer-to-peer data channel between your Hugging Face Space and local Apple Silicon. | |
| No open ports. No VPN. No SSH. Just scan and bridge. | |
| </p> | |
| <div class="bridge-demo"> | |
| <div class="bridge-visual"> | |
| <div class="bridge-node active"> | |
| <div class="node-label">HF Space</div> | |
| <div style="font-size:28px">☁️</div> | |
| <div style="font-size:11px;color:var(--cyan)">Control Plane</div> | |
| </div> | |
| <div class="bridge-connector"> | |
| <span | |
| style="font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:2px">WebRTC</span> | |
| <div class="line"></div> | |
| <span style="font-size:11px;color:var(--text-muted)">P2P</span> | |
| </div> | |
| <div class="bridge-node active"> | |
| <div class="node-label">MacBook</div> | |
| <div style="font-size:28px">💻</div> | |
| <div style="font-size:11px;color:var(--cyan)">Local Node</div> | |
| </div> | |
| <div class="bridge-connector"> | |
| <span | |
| style="font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:2px">Bonjour</span> | |
| <div class="line"></div> | |
| <span style="font-size:11px;color:var(--text-muted)">LAN</span> | |
| </div> | |
| <div class="bridge-node active"> | |
| <div class="node-label">iPhone</div> | |
| <div style="font-size:28px">📱</div> | |
| <div style="font-size:11px;color:var(--violet)">Edge Worker</div> | |
| </div> | |
| </div> | |
| <div style="text-align:center;margin-top:20px"> | |
| <p style="color:var(--text-muted);font-size:14px;max-width:500px;margin:0 auto"> | |
| The Space acts as a WebRTC signaling server. Your Mac and iPhone exchange ICE candidates, | |
| then open a direct encrypted data channel. Latency: ~5ms local, ~40ms remote. | |
| </p> | |
| </div> | |
| </div> | |
| </section> | |
| <section class="section" id="mesh"> | |
| <h2>Device Mesh</h2> | |
| <p class="lead"> | |
| Not one device. A mesh. Your MacBook runs the large model. Your iPhone handles embeddings, | |
| vision, and privacy tasks. They hand off jobs mid-stream. One logical compute unit. | |
| </p> | |
| <div class="feature-grid"> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:var(--cyan-dim);color:var(--cyan)">🔥</div> | |
| <h3>Thermal Adaptation</h3> | |
| <p>Jobs automatically migrate from overheating devices to cooler ones. The scheduler reads CPU temp, battery | |
| state, and thermal pressure in real time.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:var(--violet-dim);color:var(--violet)">🧬</div> | |
| <h3>Model Continuity</h3> | |
| <p>Same model family, auto-quantized per device. Q4_K on MacBook. Q2_K on iPhone. Seamless context handoff | |
| between quantizations.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:rgba(52,211,153,0.08);color:#34d399">📜</div> | |
| <h3>Attested Receipts</h3> | |
| <p>Every inference produces a cryptographically signed receipt. Model hash, device fingerprint, latency, and | |
| token count — verifiable by anyone.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:rgba(251,191,36,0.08);color:#fbbf24">🔒</div> | |
| <h3>Privacy Modes</h3> | |
| <p>Raw input for speed. Hash-only for audit. Local-only for sensitive data. The same API, three trust | |
| boundaries.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:var(--cyan-dim);color:var(--cyan)">⚡</div> | |
| <h3>Speculative Decoding</h3> | |
| <p>iPhone drafts tokens. MacBook verifies. 2x throughput with the same model. The small device accelerates the | |
| large one.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="icon" style="background:var(--violet-dim);color:var(--violet)">🌐</div> | |
| <h3>Zero-Config Discovery</h3> | |
| <p>Bonjour + WebRTC. Your Mac finds your iPhone on the same WiFi. Your Space finds your Mac via outbound | |
| WebSocket. No IP addresses, no port forwarding.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <section class="section"> | |
| <div | |
| style="background:linear-gradient(135deg,var(--cyan-dim),var(--violet-dim));border:1px solid rgba(0,240,255,0.15);border-radius:24px;padding:60px 40px;text-align:center"> | |
| <h2 style="margin-bottom:12px">Open the control plane</h2> | |
| <p style="color:var(--text-muted);max-width:480px;margin:0 auto 32px"> | |
| Create a session, scan the QR code with your iPhone, and your Apple hardware becomes a private Hugging Face | |
| inference endpoint. | |
| </p> | |
| <a href="/dashboard" class="btn btn-primary" style="font-size:16px;padding:16px 40px">Launch PhoneGPU</a> | |
| </div> | |
| </section> | |
| <footer> | |
| PhoneGPU Space · Membra Technologies · 2026<br> | |
| <span style="color:var(--text-muted)">Device-leased inference with attested compute receipts.</span> | |
| </footer> | |
| </div> | |
| <script> | |
| // Particle network background | |
| const canvas = document.getElementById('bg'); | |
| const ctx = canvas.getContext('2d'); | |
| let W, H, particles = [], connections = []; | |
| function resize() { | |
| W = canvas.width = window.innerWidth; | |
| H = canvas.height = window.innerHeight; | |
| } | |
| window.addEventListener('resize', resize); | |
| resize(); | |
| class Particle { | |
| constructor() { | |
| this.x = Math.random() * W; | |
| this.y = Math.random() * H; | |
| this.vx = (Math.random() - 0.5) * 0.3; | |
| this.vy = (Math.random() - 0.5) * 0.3; | |
| this.size = Math.random() * 2 + 1; | |
| this.phase = Math.random() * Math.PI * 2; | |
| } | |
| update() { | |
| this.x += this.vx; | |
| this.y += this.vy; | |
| this.phase += 0.02; | |
| if (this.x < 0 || this.x > W) this.vx *= -1; | |
| if (this.y < 0 || this.y > H) this.vy *= -1; | |
| } | |
| draw() { | |
| const opacity = 0.3 + Math.sin(this.phase) * 0.2; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); | |
| ctx.fillStyle = `rgba(0, 240, 255, ${opacity})`; | |
| ctx.fill(); | |
| } | |
| } | |
| // Create particles | |
| const count = Math.min(80, Math.floor(W * H / 15000)); | |
| for (let i = 0; i < count; i++) particles.push(new Particle()); | |
| // Mark a few as "devices" (larger, violet) | |
| const devices = [0, Math.floor(count / 3), Math.floor(count * 2 / 3)]; | |
| function animate() { | |
| ctx.fillStyle = 'rgba(3, 3, 5, 0.15)'; | |
| ctx.fillRect(0, 0, W, H); | |
| particles.forEach((p, i) => { | |
| p.update(); | |
| p.draw(); | |
| // Draw connections | |
| for (let j = i + 1; j < particles.length; j++) { | |
| const q = particles[j]; | |
| const dx = p.x - q.x, dy = p.y - q.y; | |
| const dist = Math.sqrt(dx * dx + dy * dy); | |
| if (dist < 150) { | |
| const alpha = (1 - dist / 150) * 0.08; | |
| ctx.beginPath(); | |
| ctx.moveTo(p.x, p.y); | |
| ctx.lineTo(q.x, q.y); | |
| ctx.strokeStyle = `rgba(0, 240, 255, ${alpha})`; | |
| ctx.lineWidth = 0.5; | |
| ctx.stroke(); | |
| } | |
| } | |
| }); | |
| // Draw device nodes | |
| devices.forEach(idx => { | |
| const p = particles[idx]; | |
| if (!p) return; | |
| ctx.beginPath(); | |
| ctx.arc(p.x, p.y, 6, 0, Math.PI * 2); | |
| ctx.fillStyle = 'rgba(167, 139, 250, 0.6)'; | |
| ctx.fill(); | |
| ctx.beginPath(); | |
| ctx.arc(p.x, p.y, 12, 0, Math.PI * 2); | |
| ctx.strokeStyle = 'rgba(167, 139, 250, 0.2)'; | |
| ctx.lineWidth = 1; | |
| ctx.stroke(); | |
| }); | |
| requestAnimationFrame(animate); | |
| } | |
| animate(); | |
| </script> | |
| </body> | |
| </html> |