Files
peardock-website/index.html
T
Raven Scott ff3399f551 Add full-site light theme and theme-switched screenshots
Ship a site-wide light mode with FOUC-safe persistence, tokenized
surfaces (cards, tables, cradle, docs/learn), and light product
screenshots that swap with the theme toggle including lightbox.
2026-07-16 17:59:11 -04:00

986 lines
58 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<!-- Theme: FOUC-safe bootstrap (localStorage peardock.site.theme) -->
<script>
(function () {
try {
var t = localStorage.getItem('peardock.site.theme');
if (t !== 'light' && t !== 'dark') t = 'dark';
document.documentElement.setAttribute('data-theme', t);
var meta = document.querySelector('meta[name="theme-color"]');
if (meta) meta.setAttribute('content', t === 'light' ? '#f3f5f8' : '#0a0c10');
} catch (e) {
document.documentElement.setAttribute('data-theme', 'dark');
}
})();
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>PearDock · P2P Docker ops without open ports</title>
<meta name="description" content="PearDock is peer-to-peer Docker management on HyperDHT. Use a desktop console for multi-peer fleets, the job tray, terminals, stacks, and Holesail tunnels. No open ports. No exposed Docker." />
<meta name="keywords" content="PearDock, Docker, HyperDHT, P2P, Holesail, peer-to-peer, decentralized Docker, HoneyPeer" />
<meta name="author" content="HoneyPeer, LLC" />
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
<meta name="theme-color" content="#2dd4bf" />
<meta name="color-scheme" content="dark light" />
<meta name="application-name" content="PearDock" />
<meta name="apple-mobile-web-app-title" content="PearDock" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="msapplication-TileColor" content="#2dd4bf" />
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
<meta name="format-detection" content="telephone=no" />
<link rel="canonical" href="https://peardock.boats/" />
<link rel="alternate" hreflang="en" href="https://peardock.boats/" />
<link rel="alternate" hreflang="x-default" href="https://peardock.boats/" />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="PearDock" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://peardock.boats/" />
<meta property="og:title" content="PearDock · P2P Docker ops without open ports" />
<meta property="og:description" content="PearDock is peer-to-peer Docker management on HyperDHT. Use a desktop console for multi-peer fleets, the job tray, terminals, stacks, and Holesail tunnels. No open ports. No exposed Docker." />
<meta property="og:image" content="https://peardock.boats/assets/brand/og-image.png" />
<meta property="og:image:secure_url" content="https://peardock.boats/assets/brand/og-image.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="PearDock: decentralized Docker management on HyperDHT" />
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="PearDock · P2P Docker ops without open ports" />
<meta name="twitter:description" content="PearDock is peer-to-peer Docker management on HyperDHT. Use a desktop console for multi-peer fleets, the job tray, terminals, stacks, and Holesail tunnels. No open ports. No exposed Docker." />
<meta name="twitter:image" content="https://peardock.boats/assets/brand/twitter-card.png" />
<meta name="twitter:image:alt" content="PearDock: decentralized Docker management" />
<!-- Icons & PWA -->
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
<link rel="mask-icon" href="/assets/logo/peardock-wordmark.svg" color="#2dd4bf" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://peardock.boats/#organization",
"name": "HoneyPeer, LLC",
"url": "https://peardock.boats",
"email": "[email protected]",
"address": {
"@type": "PostalAddress",
"addressRegion": "GA",
"addressLocality": "DeKalb County",
"addressCountry": "US"
},
"logo": {
"@type": "ImageObject",
"url": "https://peardock.boats/assets/logo/peardock-icon-512.png"
},
"sameAs": [
"https://git.ssh.surf/snxraven/peardock",
"https://join.discord-linux.com"
]
},
{
"@type": "WebSite",
"@id": "https://peardock.boats/#website",
"url": "https://peardock.boats",
"name": "PearDock",
"description": "PearDock is peer-to-peer Docker management on HyperDHT. Never open ports, expose Docker, or wrestle with remote access again. Noise-encrypted RPC, desktop client, and Holesail tunnels.",
"publisher": {
"@id": "https://peardock.boats/#organization"
},
"inLanguage": "en-US"
},
{
"@type": "SoftwareApplication",
"@id": "https://peardock.boats/#software",
"name": "PearDock",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Linux, macOS, Windows",
"description": "PearDock is peer-to-peer Docker management on HyperDHT. Never open ports, expose Docker, or wrestle with remote access again. Noise-encrypted RPC, desktop client, and Holesail tunnels.",
"url": "https://peardock.boats",
"downloadUrl": "https://peardock.boats/download",
"softwareVersion": "2.0",
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"author": {
"@id": "https://peardock.boats/#organization"
},
"image": "https://peardock.boats/assets/brand/og-image.png"
},
{
"@type": "WebPage",
"@id": "https://peardock.boats/#webpage",
"url": "https://peardock.boats/",
"name": "PearDock \u00b7 Decentralized Docker management",
"description": "PearDock is peer-to-peer Docker management on HyperDHT. Never open ports, expose Docker, or wrestle with remote access again. Noise-encrypted RPC, desktop client, and Holesail tunnels.",
"isPartOf": {
"@id": "https://peardock.boats/#website"
},
"about": {
"@id": "https://peardock.boats/#software"
},
"primaryImageOfPage": {
"@type": "ImageObject",
"url": "https://peardock.boats/assets/brand/og-image.png",
"width": 1200,
"height": 630
},
"inLanguage": "en-US"
}
]
}
</script>
<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@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="/src/styles/global.css" />
<link rel="stylesheet" href="/src/styles/home.css" />
<link rel="stylesheet" href="/src/styles/app-chrome.css" />
<link rel="stylesheet" href="/src/styles/theme-light.css" />
</head>
<body>
<div class="bg-mesh" aria-hidden="true"></div>
<div class="bg-grid" aria-hidden="true"></div>
<div data-nav data-prefix=""></div>
<main>
<!-- HERO -->
<section class="hero">
<div class="container-wide hero-inner">
<div class="reveal">
<div class="hero-badge">
<span class="dot"></span>
v2 · Live job tray · AGPL-3.0
</div>
<h1>
Remote Docker that<br />
<span class="gradient-text">never needs a port</span>
</h1>
<p class="lead">
PearDock is a peer-to-peer ops console for Docker on HyperDHT.
Connect with a public key, then run containers, stacks, terminals, and tunnels over Noise-encrypted RPC.<BR><BR>
<strong>No open ports. No VPN. No SaaS middleman.</strong>
</p>
<div class="hero-actions">
<a class="btn btn-primary btn-lg" href="/download">Install &amp; download</a>
<a class="btn btn-secondary btn-lg" href="#product-tour">See live demos</a>
<a class="btn btn-ghost btn-lg" href="/docs/quickstart">Quick start</a>
</div>
<div class="hero-meta">
<div class="hero-meta-item">
<strong>Multi-peer fleet</strong>
<span>Many hosts, one client</span>
</div>
<div class="hero-meta-item">
<strong>Job tray</strong>
<span>Pull · deploy · prune</span>
</div>
<div class="hero-meta-item">
<strong>Holesail</strong>
<span>Service tunnels</span>
</div>
<div class="hero-meta-item">
<strong>6 platforms</strong>
<span>Server + desktop</span>
</div>
</div>
<div class="pitch-points">
<div class="pitch-point">
<strong>Identity is a keypair</strong>
<span>Share a 64-hex public key. Nothing listens on a public Docker port.</span>
</div>
<div class="pitch-point">
<strong>Ops that feel local</strong>
<span>Dashboard, terminals, image updates, stacks, and registry vault in one dark UI.</span>
</div>
<div class="pitch-point">
<strong>Progress you can trust</strong>
<span>Multi-step job tray with hybrid layer pull and push. Not a spinner and a prayer.</span>
</div>
</div>
</div>
<div class="hero-visual reveal" data-hero-mock>
<div class="hero-glow" aria-hidden="true"></div>
<div class="hero-mock-stack">
<div class="hero-frame mock-frame">
<div class="mock-window" aria-hidden="true">
<div class="mock-titlebar">
<div class="mock-dots" aria-hidden="true"><span></span><span></span><span></span></div>
<div class="mock-titlebar-label">PearDock · Dashboard</div>
<div class="mock-titlebar-meta">
<span class="live-dot"></span>
Laptop · 14&nbsp;ms · ADMIN
</div>
</div>
<div class="mock-body">
<aside class="mock-sidebar">
<div class="mock-nav-item is-active"><span class="ico"></span> Dashboard</div>
<div class="mock-nav-item"><span class="ico"></span> Containers</div>
<div class="mock-nav-item"><span class="ico"></span> Images</div>
<div class="mock-nav-item"><span class="ico"></span> Tunnels</div>
<div class="mock-nav-item"><span class="ico"></span> Settings</div>
</aside>
<div class="mock-main">
<p class="mock-kicker">Overview</p>
<h3 class="mock-heading">Dashboard</h3>
<p class="mock-sub">Live engine health on the active peer</p>
<div class="mock-stat-row">
<div class="mock-stat-card is-run"><span class="lbl">Running</span><span class="val">5</span></div>
<div class="mock-stat-card"><span class="lbl">Stopped</span><span class="val">0</span></div>
<div class="mock-stat-card is-img"><span class="lbl">Images</span><span class="val">10</span></div>
<div class="mock-stat-card"><span class="lbl">Networks</span><span class="val">3</span></div>
</div>
<div class="mock-panels">
<div class="mock-panel">
<h4>Host load</h4>
<div class="mock-meter-row"><span>CPU</span><strong data-live-cpu>18%</strong></div>
<div class="mock-meter"><i style="width:18%" data-live-cpu-bar></i></div>
<div class="mock-meter-row"><span>Memory</span><strong data-live-mem>42%</strong></div>
<div class="mock-meter"><i style="width:42%" data-live-mem-bar></i></div>
</div>
<div class="mock-panel">
<h4>Live events</h4>
<div data-live-events>
<div class="mock-event-line"><span class="mock-event-time">now</span> peer online · Laptop</div>
<div class="mock-event-line"><span class="mock-event-time">now</span> docker ping · ok</div>
<div class="mock-event-line"><span class="mock-event-time">now</span> stats stream · active</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="hero-job-card" data-hero-job>
<div class="hero-job-head">
<strong>Job tray</strong>
<span class="hero-job-pill">Activity</span>
</div>
<p class="hero-job-label" data-hero-job-label>Pull nginx:latest…</p>
<div class="hero-job-track">
<div class="hero-job-bar" data-hero-job-bar></div>
</div>
</div>
</div>
<ul class="hero-status-bar" aria-label="Product highlights">
<li class="hero-status-item">
<span class="chip-dot" aria-hidden="true"></span>
Peer online
</li>
<li class="hero-status-item">
<span class="status-ico" aria-hidden="true">🔐</span>
Noise · E2E encrypted
</li>
<li class="hero-status-item">
<span class="status-ico" aria-hidden="true"></span>
No ports to open
</li>
</ul>
</div>
</div>
</section>
<!-- TECH STRIP -->
<div class="tech-strip">
<div class="container tech-strip-inner">
<div class="tech-item"><span></span> HyperDHT</div>
<div class="tech-item"><span></span> protomux-rpc</div>
<div class="tech-item"><span></span> compact-encoding</div>
<div class="tech-item"><span></span> dockerode</div>
<div class="tech-item"><span></span> Holesail</div>
<div class="tech-item"><span></span> Pear / Electron</div>
<div class="tech-item"><span></span> Bare runtime</div>
</div>
</div>
<!-- PRODUCT DEMOS: high fidelity app chrome -->
<section class="product-demo-section" id="product-tour" data-product-demo data-active-demo="dashboard">
<div class="container-wide">
<div class="product-demo-head reveal">
<div class="section-label" style="justify-content: center;">Product tour</div>
<h2>The real console, animated</h2>
</div>
<div class="demo-tabs reveal" role="tablist" aria-label="Product demos">
<button type="button" class="demo-tab is-active" role="tab" aria-selected="true" data-demo-tab="dashboard">Dashboard</button>
<button type="button" class="demo-tab" role="tab" aria-selected="false" data-demo-tab="jobs">Job tray · layers</button>
<button type="button" class="demo-tab" role="tab" aria-selected="false" data-demo-tab="containers">Containers</button>
<button type="button" class="demo-tab" role="tab" aria-selected="false" data-demo-tab="connect">Restore peers</button>
</div>
<!-- DASHBOARD -->
<div class="demo-stage reveal demo-panel is-active" data-demo-panel="dashboard" role="tabpanel">
<div class="demo-stage-visual">
<div class="pd-app">
<div class="pd-app-titlebar">
<div class="pd-app-dots" aria-hidden="true"><i></i><i></i><i></i></div>
<div class="pd-app-brand">
<img src="/assets/logo/peardock-icon-32.png" alt="" width="18" height="18" />
peardock <span>P2P Docker</span>
</div>
<div class="pd-app-titlebar-center">PearDock</div>
<div class="pd-app-health"><span class="dot"></span> Laptop · 14 ms · <span class="role">ADMIN</span></div>
</div>
<div class="pd-app-body">
<aside class="pd-app-side">
<div class="pd-side-label">Overview</div>
<nav class="pd-side-nav">
<div class="pd-side-link is-active"><i class="fas fa-gauge-high"></i> Dashboard</div>
<div class="pd-side-link"><i class="fas fa-network-wired"></i> Fleet</div>
<div class="pd-side-link"><i class="fas fa-bolt"></i> Events</div>
</nav>
<div class="pd-side-label">Workloads</div>
<nav class="pd-side-nav">
<div class="pd-side-link"><i class="fas fa-rocket"></i> Deploy</div>
<div class="pd-side-link"><i class="fas fa-cube"></i> Containers</div>
<div class="pd-side-link"><i class="fas fa-layer-group"></i> Images</div>
<div class="pd-side-link"><i class="fas fa-diagram-project"></i> Networks</div>
</nav>
<div class="pd-side-peer"><strong>Laptop</strong>online · admin</div>
<button type="button" class="pd-side-add"><i class="fas fa-plus"></i> Add peer</button>
</aside>
<div class="pd-app-main">
<div class="dashboard-layout dash">
<header class="dash-header">
<div>
<p class="dash-kicker">Overview</p>
<h2 class="dash-title">Dashboard</h2>
<p class="dash-subtitle">Live engine health, storage, and activity on the active peer</p>
</div>
<div class="dash-header-actions">
<span class="dash-icon-btn"><i class="fas fa-rotate"></i></span>
<span class="dash-chip-btn"><i class="fas fa-rocket"></i><span>Deploy</span></span>
</div>
</header>
<section class="dash-kpis">
<div class="dash-kpi dash-kpi--ok">
<div class="dash-kpi-icon"><i class="fas fa-play"></i></div>
<div class="dash-kpi-meta"><span class="dash-kpi-label">Running</span><span class="dash-kpi-value" data-kpi="running">5</span></div>
<div class="dash-kpi-glow"></div>
</div>
<div class="dash-kpi dash-kpi--stop">
<div class="dash-kpi-icon"><i class="fas fa-stop"></i></div>
<div class="dash-kpi-meta"><span class="dash-kpi-label">Stopped</span><span class="dash-kpi-value">0</span></div>
<div class="dash-kpi-glow"></div>
</div>
<div class="dash-kpi dash-kpi--info">
<div class="dash-kpi-icon"><i class="fas fa-layer-group"></i></div>
<div class="dash-kpi-meta"><span class="dash-kpi-label">Images</span><span class="dash-kpi-value" data-kpi="images">10</span></div>
<div class="dash-kpi-glow"></div>
</div>
<div class="dash-kpi dash-kpi--teal">
<div class="dash-kpi-icon"><i class="fas fa-diagram-project"></i></div>
<div class="dash-kpi-meta"><span class="dash-kpi-label">Networks</span><span class="dash-kpi-value" data-kpi="networks">3</span></div>
<div class="dash-kpi-glow"></div>
</div>
</section>
<section class="dash-panels">
<article class="dash-card">
<div class="dash-card-head"><div class="dash-card-title"><i class="fas fa-gears"></i><span>Engine</span></div></div>
<div class="dash-card-body">
<div class="dash-metric"><span class="dash-metric-label">Version</span><span class="dash-metric-value">27.0.2</span></div>
<div class="dash-metric"><span class="dash-metric-label">Containers</span><span class="dash-metric-value">5</span></div>
<div class="dash-metric"><span class="dash-metric-label">Running</span><span class="dash-metric-value">5</span></div>
<div class="dash-metric"><span class="dash-metric-label">Images</span><span class="dash-metric-value">10</span></div>
<div class="dash-metric"><span class="dash-metric-label">Storage driver</span><span class="dash-metric-value">overlay2</span></div>
</div>
</article>
<article class="dash-card">
<div class="dash-card-head"><div class="dash-card-title"><i class="fas fa-microchip"></i><span>Host</span></div></div>
<div class="dash-card-body">
<div class="dash-metric"><span class="dash-metric-label">Memory</span><span class="dash-metric-value">10.74 GB</span></div>
<div class="dash-metric"><span class="dash-metric-label">CPU cores</span><span class="dash-metric-value">8</span></div>
<div class="dash-metric"><span class="dash-metric-label">Operating system</span><span class="dash-metric-value">Ubuntu 26.04 LTS</span></div>
<div class="dash-metric"><span class="dash-metric-label">Architecture</span><span class="dash-metric-value">x86_64</span></div>
<div class="dash-metric"><span class="dash-metric-label">Kernel</span><span class="dash-metric-value">7.0.0-27-generic</span></div>
</div>
</article>
<article class="dash-card">
<div class="dash-card-head"><div class="dash-card-title"><i class="fas fa-hard-drive"></i><span>Disk</span></div></div>
<div class="dash-card-body">
<div class="dash-disk-row"><div class="dash-disk-top"><span>Image layers</span><strong>3.57 GB</strong></div><div class="dash-disk-bar"><i data-disk-bar data-base="78" style="width:78%"></i></div></div>
<div class="dash-disk-row"><div class="dash-disk-top"><span>Images (10)</span><strong>3.57 GB</strong></div><div class="dash-disk-bar"><i data-disk-bar data-base="78" style="width:78%"></i></div></div>
<div class="dash-disk-row"><div class="dash-disk-top"><span>Containers (5)</span><strong>50.85 MB</strong></div><div class="dash-disk-bar"><i data-disk-bar data-base="12" style="width:12%"></i></div></div>
<div class="dash-disk-row"><div class="dash-disk-top"><span>Volumes (16)</span><strong>30.95 MB</strong></div><div class="dash-disk-bar"><i data-disk-bar data-base="8" style="width:8%"></i></div></div>
<div class="dash-disk-row"><div class="dash-disk-top"><span>Build cache</span><strong>0 B</strong></div><div class="dash-disk-bar"><i data-disk-bar data-base="2" style="width:2%"></i></div></div>
</div>
</article>
<article class="dash-card">
<div class="dash-card-head"><div class="dash-card-title"><i class="fas fa-bolt"></i><span>Live events</span></div></div>
<div class="dash-card-body" data-dash-events>
<div class="event-row"><span class="event-time">04:22:09</span><span class="event-action">start</span><span class="event-target">container vpn</span></div>
<div class="event-row"><span class="event-time">04:22:09</span><span class="event-action">exec</span><span class="event-target">healthcheck vpn</span></div>
<div class="event-row"><span class="event-time">04:22:04</span><span class="event-action">die</span><span class="event-target">container vpn</span></div>
<div class="event-row"><span class="event-time">04:21:59</span><span class="event-action">create</span><span class="event-target">container api</span></div>
</div>
</article>
</section>
<footer class="dash-actions">
<div class="dash-actions-label"><i class="fas fa-bolt"></i> Quick actions</div>
<span class="dash-action"><i class="fas fa-cube"></i> Containers</span>
<span class="dash-action"><i class="fas fa-layer-group"></i> Images</span>
<span class="dash-action dash-action--warn"><i class="fas fa-broom"></i> Prune images</span>
<span class="dash-action dash-action--danger"><i class="fas fa-trash"></i> System prune</span>
</footer>
</div>
</div>
</div>
</div>
</div>
<div class="demo-stage-copy">
<h3>Dashboard that stays live</h3>
<p>KPI strip, Engine, Host, Disk, live Docker events, and quick actions. This is the same shell operators use after connect. Counts and events update continuously in this demo.</p>
<ul>
<li>Connection health: latency, Docker version, role</li>
<li>Disk bars from <code>systemDf</code> style metrics</li>
<li>Event timeline streaming from the active peer</li>
</ul>
</div>
</div>
<!-- JOB TRAY -->
<div class="demo-stage reveal demo-panel" data-demo-panel="jobs" role="tabpanel" hidden>
<div class="demo-stage-visual">
<div class="pd-app">
<div class="pd-app-titlebar">
<div class="pd-app-dots" aria-hidden="true"><i></i><i></i><i></i></div>
<div class="pd-app-brand"><img src="/assets/logo/peardock-icon-32.png" alt="" width="18" height="18" /> peardock</div>
<div class="pd-app-titlebar-center">Activity · job tray</div>
<div class="pd-app-health"><span class="dot"></span> Hybrid pull</div>
</div>
<div class="pd-job-stage">
<div class="job-panel job-panel--running" data-job-tray-demo data-job-id="demo-pull">
<div class="job-panel-header">
<div class="job-panel-title">
<span class="job-kind-icon"><i class="fas fa-download"></i></span>
<div class="job-panel-title-text">
<strong>Pull image</strong>
<div class="job-panel-subtitle">nginx:latest</div>
</div>
</div>
<div class="job-panel-header-right">
<span class="job-auto-dismiss-hint" hidden>Closing in 3s…</span>
<span class="job-steps-chip">1/4</span>
<span class="badge bg-primary job-status-badge">running</span>
<button type="button" class="job-dismiss-btn" tabindex="-1" aria-hidden="true"><i class="fas fa-times"></i></button>
</div>
</div>
<div class="job-steps">
<div class="job-step job-step--active" data-job-step>
<span class="job-step-icon"><span class="job-spinner"><span class="job-spinner-ring"></span></span></span>
<span class="job-step-label">Resolve &amp; authenticate</span>
<span class="job-step-detail text-muted"></span>
</div>
<div class="job-step job-step--pending" data-job-step>
<span class="job-step-icon"><i class="fas fa-circle text-muted"></i></span>
<span class="job-step-label">Pull layers (hybrid progress)</span>
<span class="job-step-detail text-muted"></span>
</div>
<div class="job-step job-step--pending" data-job-step>
<span class="job-step-icon"><i class="fas fa-circle text-muted"></i></span>
<span class="job-step-label">Create container</span>
<span class="job-step-detail text-muted"></span>
</div>
<div class="job-step job-step--pending" data-job-step>
<span class="job-step-icon"><i class="fas fa-circle text-muted"></i></span>
<span class="job-step-label">Start &amp; publish ports</span>
<span class="job-step-detail text-muted"></span>
</div>
</div>
<div class="pull-progress pull-progress--resolving" data-pull-progress data-pull-phase="resolving">
<div class="pull-progress-summary">
<span class="pull-progress-phase">Resolving</span>
<span class="pull-progress-meta">nginx:latest</span>
<span class="pull-progress-pct"></span>
</div>
<div class="pull-progress-bar"><div class="pull-progress-bar-fill" style="width:8%"></div></div>
<div class="pull-progress-track" aria-hidden="true">
<span class="pull-layer-pip pull-layer-pip--idle"></span>
<span class="pull-layer-pip pull-layer-pip--idle"></span>
<span class="pull-layer-pip pull-layer-pip--idle"></span>
<span class="pull-layer-pip pull-layer-pip--idle"></span>
<span class="pull-layer-pip pull-layer-pip--idle"></span>
<span class="pull-layer-pip pull-layer-pip--idle"></span>
</div>
<div class="pull-progress-layers" aria-label="Active layers">
<div class="pull-layer pull-layer--empty"><span class="pull-layer-id"></span><div class="pull-layer-bar"><div class="pull-layer-bar-fill" style="width:0%"></div></div><span class="pull-layer-meta"></span></div>
<div class="pull-layer pull-layer--empty"><span class="pull-layer-id"></span><div class="pull-layer-bar"><div class="pull-layer-bar-fill" style="width:0%"></div></div><span class="pull-layer-meta"></span></div>
<div class="pull-layer pull-layer--empty"><span class="pull-layer-id"></span><div class="pull-layer-bar"><div class="pull-layer-bar-fill" style="width:0%"></div></div><span class="pull-layer-meta"></span></div>
<div class="pull-layer pull-layer--empty"><span class="pull-layer-id"></span><div class="pull-layer-bar"><div class="pull-layer-bar-fill" style="width:0%"></div></div><span class="pull-layer-meta"></span></div>
</div>
<div class="pull-progress-waiting pull-progress-waiting--empty">&nbsp;</div>
<div class="pull-progress-activity">Resolving image nginx:latest…</div>
</div>
<details class="job-log-details" open>
<summary class="job-log-summary"><span class="job-log-summary-label">Live output</span></summary>
<div class="job-log" role="log"></div>
</details>
</div>
</div>
</div>
</div>
<div class="demo-stage-copy">
<h3>Hybrid pull, real layer UI</h3>
<p>
The same job panel as the app. You get a step timeline, overall bar, layer pip track, and four fixed layer slots with per layer download and extract bars. Waiting count and activity line follow. Create and start run after the pull.
</p>
<ul>
<li>Per-layer MB progress (download → extract)</li>
<li>Pip track colors: wait / download / extract / done</li>
<li>Stable height while pulling (no layout jump)</li>
<li>Live log lines under the progress card</li>
</ul>
</div>
</div>
<!-- CONTAINERS -->
<div class="demo-stage reveal demo-panel" data-demo-panel="containers" role="tabpanel" hidden>
<div class="demo-stage-visual">
<div class="pd-app">
<div class="pd-app-titlebar">
<div class="pd-app-dots" aria-hidden="true"><i></i><i></i><i></i></div>
<div class="pd-app-brand"><img src="/assets/logo/peardock-icon-32.png" alt="" width="18" height="18" /> peardock</div>
<div class="pd-app-titlebar-center">Containers</div>
<div class="pd-app-health"><span class="dot"></span> Image updates</div>
</div>
<div class="pd-app-body">
<aside class="pd-app-side">
<div class="pd-side-label">Workloads</div>
<nav class="pd-side-nav">
<div class="pd-side-link"><i class="fas fa-gauge-high"></i> Dashboard</div>
<div class="pd-side-link is-active"><i class="fas fa-cube"></i> Containers</div>
<div class="pd-side-link"><i class="fas fa-layer-group"></i> Images</div>
<div class="pd-side-link"><i class="fas fa-hard-drive"></i> Volumes</div>
</nav>
<div class="pd-side-peer"><strong>Laptop</strong>5 running</div>
<button type="button" class="pd-side-add"><i class="fas fa-plus"></i> Add peer</button>
</aside>
<div class="pd-app-main">
<div class="pd-containers-wrap">
<div class="pd-containers-toolbar">
<h3><i class="fas fa-cube"></i> Containers</h3>
<div class="pd-filter-seg">
<button type="button" class="is-active">All</button>
<button type="button">Running</button>
<button type="button">Exited</button>
</div>
</div>
<table class="pd-table">
<thead>
<tr>
<th>Name</th>
<th>State</th>
<th>Image</th>
<th>Ports</th>
<th>Updates</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">vpn</td>
<td><span class="pd-badge pd-badge--running">running</span></td>
<td class="mono">gluetun:latest</td>
<td class="mono">none</td>
<td><span class="pd-update pd-update--ok" title="Up to date"><i class="fas fa-check"></i></span></td>
<td><div class="pd-row-actions"><span><i class="fas fa-terminal"></i></span><span><i class="fas fa-file-lines"></i></span><span><i class="fas fa-ellipsis"></i></span></div></td>
</tr>
<tr>
<td class="name">apache-httpd</td>
<td><span class="pd-badge pd-badge--running">running</span></td>
<td class="mono">httpd:latest</td>
<td class="mono">8080→80</td>
<td><span class="pd-update pd-update--avail" title="Update available"><i class="fas fa-arrow-up"></i></span></td>
<td><div class="pd-row-actions"><span><i class="fas fa-terminal"></i></span><span><i class="fas fa-file-lines"></i></span><span><i class="fas fa-ellipsis"></i></span></div></td>
</tr>
<tr>
<td class="name">api</td>
<td><span class="pd-badge pd-badge--running">running</span></td>
<td class="mono">ghcr.io/app:1.4</td>
<td class="mono">3000→3000</td>
<td><span class="pd-update pd-update--ok"><i class="fas fa-check"></i></span></td>
<td><div class="pd-row-actions"><span><i class="fas fa-terminal"></i></span><span><i class="fas fa-file-lines"></i></span><span><i class="fas fa-ellipsis"></i></span></div></td>
</tr>
<tr>
<td class="name">worker</td>
<td><span class="pd-badge pd-badge--exited">exited</span></td>
<td class="mono">node:20</td>
<td class="mono">none</td>
<td><span class="pd-update pd-update--avail" title="Update available"><i class="fas fa-arrow-up"></i></span></td>
<td><div class="pd-row-actions"><span><i class="fas fa-play"></i></span><span><i class="fas fa-file-lines"></i></span><span><i class="fas fa-ellipsis"></i></span></div></td>
</tr>
<tr>
<td class="name">redis</td>
<td><span class="pd-badge pd-badge--running">running</span></td>
<td class="mono">redis:7.0.7</td>
<td class="mono">6379→6379</td>
<td><span class="pd-update pd-update--ok"><i class="fas fa-check"></i></span></td>
<td><div class="pd-row-actions"><span><i class="fas fa-terminal"></i></span><span><i class="fas fa-file-lines"></i></span><span><i class="fas fa-ellipsis"></i></span></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="demo-stage-copy">
<h3>Containers with update digests</h3>
<p>State badges, published ports, and the Updates column (✓ up to date, ↑ pull available). Matches the real list, with terminal and logs actions per row.</p>
<ul>
<li>Registry digest compare for each tag</li>
<li>Click ↑ to pull via the job tray</li>
<li>Bulk actions and role-gated remove</li>
</ul>
</div>
</div>
<!-- CONNECT / RESTORE -->
<div class="demo-stage reveal demo-panel" data-demo-panel="connect" role="tabpanel" hidden>
<div class="demo-stage-visual">
<div class="pd-app">
<div class="pd-app-titlebar">
<div class="pd-app-dots" aria-hidden="true"><i></i><i></i><i></i></div>
<div class="pd-app-brand"><img src="/assets/logo/peardock-icon-32.png" alt="" width="18" height="18" /> peardock</div>
<div class="pd-app-titlebar-center">Restoring connections</div>
<div class="pd-app-health"><span class="dot"></span> Boot</div>
</div>
<div class="pd-connect-stage">
<div class="pd-connect-card">
<div class="orb">
<span class="job-spinner job-spinner--xl"><span class="job-spinner-ring"></span></span>
</div>
<h3>Restoring connections</h3>
<p class="lead">Reconnecting to your saved servers over HyperDHT…</p>
<div class="pd-connect-status">
<span class="dot"></span>
<span data-connect-status>Dialing HyperDHT…</span>
</div>
<div class="pd-connect-progress">
<div class="track"><div class="bar" data-connect-bar style="width:15%"></div></div>
<div class="meta"><strong data-connect-count>0 of 2</strong><span>peers</span></div>
</div>
</div>
</div>
</div>
</div>
<div class="demo-stage-copy">
<h3>Boot restore, not a blank splash</h3>
<p>On launch the client re-dials saved peers with live status and progress. It lands on the dashboard when a peer is online.</p>
<ul>
<li>Last-active peer preferred</li>
<li>Auto-reconnect every 5s if the link drops</li>
<li>pd1 invites for operator access without sharing the seed</li>
</ul>
</div>
</div>
</div>
</section>
<!-- FEATURES -->
<section class="section" id="features">
<div class="container">
<div class="reveal">
<div class="section-label">Features</div>
<h2>Full Engine coverage.<br />Zero ports to open.</h2>
<p class="lead mt-4">
Containers, images, volumes, networks, stacks, Swarm, terminals, logs, and GitOps.
Registry browser and vault. Image update checks. Portainer-style templates. Roles and Holesail tunnels.
All in a desktop console built for real ops.
Remote Docker without port forwards, public <code>dockerd</code>, or a permanent VPN.
</p>
</div>
<div class="features-grid">
<article class="card reveal">
<div class="card-icon"></div>
<h3>No ports. No VPN.</h3>
<p>Server identity is a HyperDHT keypair. Share the public key. Peers holepunch. Nothing phones home. Nothing listens on a public Docker port.</p>
</article>
<article class="card reveal">
<div class="card-icon">🔐</div>
<h3>Noise encryption</h3>
<p>Every control connection is end-to-end encrypted. Roles cover viewer, operator, and admin. Allowlists, pd1 invites, and audit logging help multi-operator fleets stay safe.</p>
</article>
<article class="card reveal">
<div class="card-icon">🚢</div>
<h3>Docker ops console</h3>
<p>Deploy templates. Add containers. Recreate and prune. Stack env files, image update indicators, secrets, configs, and schedules. Built for real operators.</p>
</article>
<article class="card reveal">
<div class="card-icon"></div>
<h3>Holesail tunnels</h3>
<p>Reach published services over <code>hs://</code> keys with no inbound firewall rules. This is a separate data plane next to the RPC control plane.</p>
</article>
<article class="card reveal">
<div class="card-icon">🖥️</div>
<h3>Desktop client</h3>
<p>Electron or Pear. Multi-peer fleet. Multi-step job tray with hybrid pull progress. Live stats, terminals, and OTA-ready packaging.</p>
</article>
<article class="card reveal">
<div class="card-icon">📦</div>
<h3>Standalone binaries</h3>
<p>Cross-built server (Bare) and client (Electron) for linux, darwin, and win32 on x64 and arm64. Rolling releases come from CI.</p>
</article>
</div>
<div class="stats-row reveal">
<div class="stat"><strong>6</strong><span>64-bit host targets</span></div>
<div class="stat"><strong>v2</strong><span>HyperDHT + protomux-rpc</span></div>
<div class="stat"><strong>3</strong><span>ACL roles</span></div>
<div class="stat"><strong>0</strong><span>Ports to open</span></div>
</div>
</div>
</section>
<!-- ARCHITECTURE + HOW IT WORKS -->
<section class="section arch-section" id="architecture">
<div class="container">
<div class="reveal text-center" style="max-width: 640px; margin: 0 auto;">
<div class="section-label" style="justify-content: center;">How it works</div>
<h2>Keys, peers, Docker.<br />Still zero open ports.</h2>
<p class="lead" style="margin: 1rem auto 0;">
Control traffic uses HyperDHT and protomux-rpc. Service access uses Holesail.
Both are peer-to-peer.
No inbound firewall rules. No public Docker API.
</p>
</div>
<div class="how-flow reveal" data-how-flow>
<article class="how-step is-active" data-how-step>
<div class="how-step-num">1</div>
<h3>Run the server</h3>
<p>On a host with Docker, install via one-liner or binary. Identity is a HyperDHT keypair printed at start: <code>SERVER_PUBLIC_KEY</code> and seed.</p>
</article>
<article class="how-step" data-how-step>
<div class="how-step-num">2</div>
<h3>Launch the client</h3>
<p>Electron desktop (or Pear). Paste a public key, key + seed, or a <code>pd1.</code> invite. Multi-peer fleet lives in the sidebar.</p>
</article>
<article class="how-step" data-how-step>
<div class="how-step-num">3</div>
<h3>Operate</h3>
<p>Deploy, terminal, logs, stacks, registry, tunnels. Long work streams through the job tray with real progress.</p>
</article>
</div>
<div class="arch-diagram reveal">
<div class="arch-node">
<div class="node-icon"></div>
<h3>Desktop client</h3>
<p>Electron / Pear · multi-peer · job tray · registry</p>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 48 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 12h40M34 4l10 8-10 8"/></svg>
RPC
</div>
<div class="arch-node">
<div class="node-icon"></div>
<h3>peardock server</h3>
<p>HyperDHT listen · ACL · handlers · vault · registry</p>
</div>
<div class="arch-arrow">
<svg viewBox="0 0 48 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 12h40M34 4l10 8-10 8"/></svg>
Socket
</div>
<div class="arch-node">
<div class="node-icon">🐳</div>
<h3>Docker Engine</h3>
<p>dockerode · compose · swarm</p>
</div>
</div>
<div class="arch-details reveal">
<div class="arch-detail">
<h4>Control plane</h4>
<p>Handshake, containers (including image update checks), deploy stacks and templates, logs, and stats pushes. Terminal streams, registry vault, remote browser, and peer policy. Protocol version is negotiated on connect.</p>
</div>
<div class="arch-detail">
<h4>Data / tunnels</h4>
<p>Holesail L4 proxy binds published container or host ports to <code>hs://</code> capabilities. Opt out with <code>ENABLE_HOLESAIL=0</code>.</p>
</div>
</div>
<div class="text-center mt-6 reveal">
<a class="btn btn-secondary" href="/learn/">How PearDock works →</a>
<a class="btn btn-ghost" href="/docs/architecture">Architecture reference →</a>
</div>
</div>
</section>
<!-- DEEP FEATURES -->
<section class="section">
<div class="container">
<div class="feature-row reveal">
<div class="feature-copy">
<div class="section-label">Fleet</div>
<h2>Multi-peer. Multi-host.<br />One client.</h2>
<p class="lead">Connect to many servers at once. Tag environments (prod / staging / lab). Switch contexts without losing job history or health signals. Manage saved hosts under Settings → Peers. Server ACL lives under Access.</p>
<ul class="feature-list">
<li>Peer disk cache under <code>~/.config/peardock</code></li>
<li>Connection health badge: latency, Docker status, role</li>
<li>pd1 invites, revoke, allowlist for multi-operator setups</li>
<li>Full Registry view: encrypted vault, Hub search, remote catalog/tags/manifests</li>
</ul>
</div>
<div class="feature-visual" data-lightbox="/assets/screenshots/screenshot-1.png" data-lightbox-dark="/assets/screenshots/screenshot-1.png" data-lightbox-light="/assets/screenshots/screenshot-1-light.png">
<img src="/assets/screenshots/screenshot-1.png" data-shot-dark="/assets/screenshots/screenshot-1.png" data-shot-light="/assets/screenshots/screenshot-1-light.png" alt="PearDock multi-host fleet and connection UI" />
</div>
</div>
<div class="feature-row reverse reveal">
<div class="feature-copy">
<div class="section-label">Operations</div>
<h2>Deploy like you mean it.</h2>
<p class="lead">Portainer-style templates and blank Add container. Compose stacks with env files and overrides. Image update indicators, system prune, and volume file browser. Multi-step job tray with hybrid pull progress. <a href="#product-tour">See the demo</a>.</p>
<ul class="feature-list">
<li>Container and stack templates; always-pull on create / duplicate</li>
<li>GitOps-friendly stack deploy; remove cleans project networks</li>
<li>Swarm services, nodes, secrets, configs, scale</li>
<li>Job tray steps + layer pull/push progress; role-gated destructive actions</li>
</ul>
</div>
<div class="feature-visual" data-lightbox="/assets/screenshots/screenshot-2.png" data-lightbox-dark="/assets/screenshots/screenshot-2.png" data-lightbox-light="/assets/screenshots/screenshot-2-light.png">
<img src="/assets/screenshots/screenshot-2.png" data-shot-dark="/assets/screenshots/screenshot-2.png" data-shot-light="/assets/screenshots/screenshot-2-light.png" alt="PearDock deploy templates and operations UI" />
</div>
</div>
<div class="feature-row reveal">
<div class="feature-copy">
<div class="section-label">Tunnels</div>
<h2>Share a service.<br />Never open a port.</h2>
<p class="lead">
Create a Holesail tunnel from a container or host port. Copy the <code>hs://</code> URL.
Remote peers bind locally. You never punch a firewall hole or expose Docker to the internet.
</p>
<ul class="feature-list">
<li>No inbound port forwards. P2P hole punching instead.</li>
<li>Secure mode by default (capability is not a raw listen key)</li>
<li>SSRF guard: loopback and allowlisted hosts only</li>
<li>Max concurrent tunnels. Audited create and close.</li>
</ul>
<a class="btn btn-ghost mt-4" href="docs/holesail.html">Holesail guide →</a>
</div>
<div class="feature-visual" data-lightbox="/assets/screenshots/screenshot-3.png" data-lightbox-dark="/assets/screenshots/screenshot-3.png" data-lightbox-light="/assets/screenshots/screenshot-3-light.png">
<img src="/assets/screenshots/screenshot-3.png" data-shot-dark="/assets/screenshots/screenshot-3.png" data-shot-light="/assets/screenshots/screenshot-3-light.png" alt="Holesail tunnels UI" />
</div>
</div>
</div>
</section>
<!-- SCREENSHOTS -->
<section class="section" id="screenshots" style="background: var(--bg-secondary); border-top: 1px solid var(--border);">
<div class="container-wide">
<div class="reveal">
<div class="section-label">Product</div>
<h2>See it in action</h2>
<p class="lead mt-4">Dense, operator-first UI for long sessions. Screenshots follow the site theme. Click any shot for a full-size view.</p>
</div>
<div class="shots-grid">
<div class="shot reveal" data-lightbox="/assets/screenshots/screenshot-0.png" data-lightbox-dark="/assets/screenshots/screenshot-0.png" data-lightbox-light="/assets/screenshots/screenshot-0-light.png" role="button" tabindex="0" aria-label="Open PearDock containers overview screenshot">
<img src="/assets/screenshots/screenshot-0.png" data-shot-dark="/assets/screenshots/screenshot-0.png" data-shot-light="/assets/screenshots/screenshot-0-light.png" alt="PearDock containers overview with image update indicators" loading="lazy" />
</div>
<div class="shot reveal" data-lightbox="/assets/screenshots/screenshot-4.png" data-lightbox-dark="/assets/screenshots/screenshot-4.png" data-lightbox-light="/assets/screenshots/screenshot-4-light.png" role="button" tabindex="0" aria-label="Open PearDock container detail screenshot">
<img src="/assets/screenshots/screenshot-4.png" data-shot-dark="/assets/screenshots/screenshot-4.png" data-shot-light="/assets/screenshots/screenshot-4-light.png" alt="PearDock container detail view" loading="lazy" />
</div>
<div class="shot reveal" data-lightbox="/assets/screenshots/screenshot-5.png" data-lightbox-dark="/assets/screenshots/screenshot-5.png" data-lightbox-light="/assets/screenshots/screenshot-5-light.png" role="button" tabindex="0" aria-label="Open PearDock logs and terminal screenshot">
<img src="/assets/screenshots/screenshot-5.png" data-shot-dark="/assets/screenshots/screenshot-5.png" data-shot-light="/assets/screenshots/screenshot-5-light.png" alt="PearDock logs and interactive terminal" loading="lazy" />
</div>
<div class="shot reveal" data-lightbox="/assets/screenshots/screenshot-2.png" data-lightbox-dark="/assets/screenshots/screenshot-2.png" data-lightbox-light="/assets/screenshots/screenshot-2-light.png" role="button" tabindex="0" aria-label="Open PearDock deploy templates screenshot">
<img src="/assets/screenshots/screenshot-2.png" data-shot-dark="/assets/screenshots/screenshot-2.png" data-shot-light="/assets/screenshots/screenshot-2-light.png" alt="PearDock deploy templates and stack forms" loading="lazy" />
</div>
<div class="shot reveal" data-lightbox="/assets/screenshots/screenshot-1.png" data-lightbox-dark="/assets/screenshots/screenshot-1.png" data-lightbox-light="/assets/screenshots/screenshot-1-light.png" role="button" tabindex="0" aria-label="Open PearDock fleet and registry screenshot">
<img src="/assets/screenshots/screenshot-1.png" data-shot-dark="/assets/screenshots/screenshot-1.png" data-shot-light="/assets/screenshots/screenshot-1-light.png" alt="PearDock multi-host fleet, registry, and settings UI" loading="lazy" />
</div>
</div>
</div>
</section>
<!-- QUICK START TEASER -->
<section class="section" id="quickstart">
<div class="container">
<div class="reveal">
<div class="section-label">Quick start</div>
<h2>Install in one line. Connect in three steps.</h2>
<p class="lead mt-4">
No public IP gymnastics. No open ports. No VPN checklist.
The interactive installer pulls rolling binaries. It wires Linux systemd and the docker group for the server, or installs a desktop client.
</p>
</div>
<div class="card reveal install-card">
<pre><code>curl -fsSL https://install.peardock.boats | bash</code></pre>
<pre><code># Non-interactive
curl -fsSL https://install.peardock.boats | bash -s -- --server --yes
curl -fsSL https://install.peardock.boats | bash -s -- --client --yes</code></pre>
</div>
<div class="features-grid features-grid--steps">
<article class="card reveal">
<span class="badge mb-4">01</span>
<h3>Server online</h3>
<p class="mt-4">Run <code>systemctl status peardock</code>, then check <code>/opt/peardock/.env</code> for <code>SERVER_PUBLIC_KEY</code> and <code>SERVER_SEED</code>.</p>
</article>
<article class="card reveal">
<span class="badge mb-4">02</span>
<h3>Launch the client</h3>
<p class="mt-4">Open <code>peardock.app</code> (macOS) or <code>peardock-client</code> (Linux). Or download from <a href="download.html">Download</a>.</p>
</article>
<article class="card reveal">
<span class="badge mb-4">03</span>
<h3>Connect</h3>
<p class="mt-4">Add peer: public key (viewer), key + seed (admin), or a full <code>pd1.</code> invite. Peers auto-reconnect every 5s if the link drops.</p>
</article>
</div>
<div class="text-center mt-6 reveal">
<a class="btn btn-primary" href="docs/quickstart.html">Full quick start guide</a>
<a class="btn btn-secondary" href="download.html">Install &amp; download</a>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-band">
<div class="container">
<div class="cta-card reveal">
<div class="badge mb-4">Open source · AGPL-3.0</div>
<h2>Remote Docker without remote-access drama.</h2>
<p class="lead">
Never open ports or expose your Engine again. Just keys and peers.
Grab rolling binaries for six hosts, or build from source.
</p>
<div class="cta-actions">
<a class="btn btn-primary btn-lg" href="download.html">Download peardock</a>
<a class="btn btn-secondary btn-lg" href="docs/index.html">Browse docs</a>
</div>
</div>
</div>
</section>
</main>
<div data-footer data-prefix=""></div>
<script type="module" src="/src/js/site.js"></script>
<script type="module" src="/src/js/home-demos.js"></script>
</body>
</html>