mac-compute-space / app /static /index.html
josephrw's picture
Upload folder using huggingface_hub
c4916b2 verified
Raw
History Blame Contribute Delete
16.2 kB
<!DOCTYPE html>
<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>