From 7969f7897a7f47df73bd0fd008ee1ea65964eb57 Mon Sep 17 00:00:00 2001
From: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Date: Fri, 25 Sep 2026 22:11:44 +0800
Subject: [PATCH 1/2] Make Mac App download prominent on homepage
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
---
.../site/scripts/analytics-client.js | 5 ++
apps/presentation/site/src/App.tsx | 45 ++++++++-----
apps/presentation/site/src/styles.css | 63 ++++++++++++++++++-
3 files changed, 96 insertions(+), 17 deletions(-)
diff --git a/apps/presentation/site/scripts/analytics-client.js b/apps/presentation/site/scripts/analytics-client.js
index 9fe63a89a7..8fed980743 100644
--- a/apps/presentation/site/scripts/analytics-client.js
+++ b/apps/presentation/site/scripts/analytics-client.js
@@ -125,6 +125,11 @@
const anchor = target?.closest("a[href]");
if (!anchor) return;
const url = new URL(anchor.href);
+ if (marked === "desktop_download" && url.hostname === "github.com" &&
+ url.pathname === "/loopx-project/loopx/releases/latest/download/LoopX.app.zip") {
+ event("desktop_download", { platform: "macos", artifact: "app_zip" });
+ return;
+ }
if (url.hostname === "github.com" && /^\/(?:loopx-project|huangruiteng)\/loopx(?:\/|$)/.test(url.pathname)) {
event("github_click", { destination: url.pathname.includes("packages/dsh-loopx-plugin") ? "dsh_plugin" : "repository" });
} else if (url.origin === location.origin && url.pathname.startsWith("/loopx/docs/") && url.pathname !== location.pathname) {
diff --git a/apps/presentation/site/src/App.tsx b/apps/presentation/site/src/App.tsx
index 960df9ba75..ec8c4a17e5 100644
--- a/apps/presentation/site/src/App.tsx
+++ b/apps/presentation/site/src/App.tsx
@@ -5,6 +5,7 @@ import {
ChevronRight,
Clipboard,
Code2,
+ Download,
ExternalLink,
FileCheck2,
GitBranch,
@@ -60,6 +61,9 @@ cd /path/to/your-project
loopx connect
loopx status`;
+const macAppDownloadUrl = "https://github.com/loopx-project/loopx/releases/latest/download/LoopX.app.zip";
+const macAppGuideUrl = "https://github.com/loopx-project/loopx/blob/main/apps/desktop/loopx-control-plane/README.md";
+
const content = {
en: {
nav: ["Product", "Workflow", "Learn"],
@@ -71,6 +75,12 @@ const content = {
},
body: "Turn complex work into durable goals, coordinated tasks, and reviewable results. LoopX keeps your agents moving across sessions. You keep the judgment.",
copy: "Get started",
+ mac: {
+ download: "Download for Mac",
+ compact: "Mac App",
+ note: "Apple Silicon preview (.app.zip) · Python 3.11+ required.",
+ guide: "Install and first launch",
+ },
setup: {
eyebrow: "Set up LoopX",
title: "Choose how you want to start.",
@@ -184,6 +194,12 @@ const content = {
},
body: "把复杂工作变成持久的目标、协同的任务和可审查的成果。跨越会话,Agent 接着做;关键判断,始终由你掌握。",
copy: "开始使用",
+ mac: {
+ download: "下载 Mac App",
+ compact: "Mac App",
+ note: "Apple Silicon 预览版(.app.zip)· 需要 Python 3.11+。",
+ guide: "安装与首次启动",
+ },
setup: {
eyebrow: "设置 LoopX",
title: "选择你的开始方式。",
@@ -303,14 +319,6 @@ function ProductMark() {
);
}
-function GitHubIcon() {
- return (
-
- );
-}
-
function StatusPill({
tone,
children,
@@ -795,6 +803,7 @@ export function App() {
{language === "zh" ? "探索" : "Explore"}
Blog
Docs
+ GitHub
diff --git a/apps/presentation/site/src/styles.css b/apps/presentation/site/src/styles.css
index 0c0ed4328b..6435692214 100644
--- a/apps/presentation/site/src/styles.css
+++ b/apps/presentation/site/src/styles.css
@@ -160,7 +160,7 @@ button {
font-size: 13px;
}
-.github-button {
+.header-download {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -174,11 +174,15 @@ button {
transition: background 160ms ease, transform 160ms ease;
}
-.github-button:hover {
+.header-download:hover {
background: #333;
transform: translateY(-1px);
}
+.header-download-compact {
+ display: none;
+}
+
.menu-button {
display: none;
width: 40px;
@@ -307,6 +311,15 @@ body[data-language="zh"] .hero h1 {
line-height: 1.7;
}
+.hero-footnote a {
+ display: inline-flex;
+ align-items: center;
+ gap: 3px;
+ color: var(--ink);
+ text-decoration: underline;
+ text-underline-offset: 3px;
+}
+
.hero-system {
position: relative;
z-index: 3;
@@ -371,6 +384,32 @@ body[data-language="zh"] .hero h1 {
margin-top: 32px;
}
+.hero-demo {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-height: 44px;
+ padding: 0 8px;
+ color: var(--body);
+ font-size: 13px;
+ font-weight: 500;
+}
+
+.hero-demo:hover {
+ color: var(--ink);
+ text-decoration: underline;
+ text-underline-offset: 4px;
+}
+
+.header-download:focus-visible,
+.hero-actions a:focus-visible,
+.hero-actions button:focus-visible,
+.hero-footnote a:focus-visible {
+ outline: 2px solid var(--blue);
+ outline-offset: 3px;
+}
+
.button {
display: inline-flex;
align-items: center;
@@ -1768,10 +1807,18 @@ body.dialog-open {
height: 64px;
}
- .github-button {
+ .header-download {
+ padding: 0 12px;
+ }
+
+ .header-download-full {
display: none;
}
+ .header-download-compact {
+ display: inline;
+ }
+
.hero {
min-height: 0;
padding: 48px 0 56px;
@@ -1794,6 +1841,10 @@ body.dialog-open {
flex-direction: column;
}
+ .hero-demo {
+ align-self: flex-start;
+ }
+
.button {
width: 100%;
}
@@ -2019,6 +2070,12 @@ body.dialog-open {
}
}
+@media (max-width: 359px) {
+ .header-download {
+ display: none;
+ }
+}
+
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
From f0d5ab3fd428e1d7ea9713131e9ea532b69a818d Mon Sep 17 00:00:00 2001
From: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Date: Fri, 25 Sep 2026 22:12:26 +0800
Subject: [PATCH 2/2] Document and verify Mac download entry
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
---
apps/presentation/site/README.md | 10 +++++++---
apps/presentation/site/scripts/analytics-smoke.mjs | 4 ++++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/apps/presentation/site/README.md b/apps/presentation/site/README.md
index 08462a4c63..22cb3a5c88 100644
--- a/apps/presentation/site/README.md
+++ b/apps/presentation/site/README.md
@@ -46,11 +46,14 @@ Keep source-document exports, private references, and unreviewed media outside
the public tree. Follow `docs/development/design.md` and obtain first-screen
review before changing the Blog or its homepage entry.
-The first-run CTA opens one setup dialog with a recommended Agent path and a
+The header and primary homepage CTA download the latest Apple Silicon Mac App
+preview through the release's stable `LoopX.app.zip` asset name. The homepage
+states the Python 3.11+ prerequisite and links to the desktop first-launch guide.
+The adjacent first-run CTA opens one setup dialog with an Agent path and a
manual Shell path. The Agent option copies the localized, public-safe setup
contract; the Shell option copies the commands shown in the terminal section.
-The `See in action` CTA scrolls to the public evidence showcase and restarts the
-Issue Fix replay.
+The `See in action` link scrolls to the public evidence showcase and restarts
+the Issue Fix replay.
The homepage control-plane diagrams are synthetic UI. Finite, tabbed terminal
replays summarize two public README trajectories; they are curated projections,
@@ -122,6 +125,7 @@ in tests; production collection still needs a real post-deployment check.
| `page_view` | A canonical public page was opened; hash and locale-only changes do not add views. |
| `setup_open` | Opened the homepage setup dialog. |
| `setup_copy` | Successfully copied an Agent prompt or Shell setup command (`setup_method`). |
+| `desktop_download` | Clicked an official Mac App download link (`platform`, `artifact`); this records intent, not a completed download. |
| `showcase_open` | Followed the homepage demonstration CTA. |
| `github_click` | Clicked a repository or DSH plugin link (`destination`). |
| `docs_open` | Followed a link into documentation. |
diff --git a/apps/presentation/site/scripts/analytics-smoke.mjs b/apps/presentation/site/scripts/analytics-smoke.mjs
index 60c021758d..be66748f7c 100644
--- a/apps/presentation/site/scripts/analytics-smoke.mjs
+++ b/apps/presentation/site/scripts/analytics-smoke.mjs
@@ -94,11 +94,15 @@ try {
window.dispatchEvent(new CustomEvent("loopx:setup-copy", { detail: "never-send-this" }));
});
await page.getByRole("button", { name: "Close setup", exact: true }).click();
+ await page.evaluate(() => document.querySelector(".hero-download")?.addEventListener("click", (event) => event.preventDefault()));
+ await page.locator(".hero-download").click();
await page.locator(".language-toggle").click();
const rows = await page.evaluate(() => window.dataLayer.map((args) => [...args]));
assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "page_view").length, 1);
assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "setup_open").length, 1);
assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "setup_copy").length, 1);
+ assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "desktop_download").length, 1);
+ assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "github_click").length, 0, "Mac download is not a repository visit");
assert(!JSON.stringify(rows).includes("never-send-this") && !JSON.stringify(rows).includes("private-task"));
assert.equal(rows.find((r) => r[0] === "config")[2].allow_google_signals, false);
await page.evaluate(() => {