Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added docs/.nojekyll
Empty file.
333 changes: 333 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>dsx — Claude Design sync, without the bytes touching a model</title>
<meta name="description" content="A single Go binary that syncs files between a Claude Design project and a local directory. A pull that costs an agent ~665k tokens costs dsx one summary line.">
<link rel="canonical" href="https://somework.github.io/dsx/">
<meta property="og:type" content="website">
<meta property="og:title" content="dsx — Claude Design sync, without the bytes touching a model">
<meta property="og:description" content="A pull that costs an agent ~665k tokens costs dsx one summary line. Single Go binary, stdlib only. Unofficial.">
<meta property="og:url" content="https://somework.github.io/dsx/">
<meta property="og:image" content="https://somework.github.io/dsx/demo.gif">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="dsx — Claude Design sync, without the bytes touching a model">
<meta name="twitter:description" content="A pull that costs an agent ~665k tokens costs dsx one summary line. Single Go binary, stdlib only.">
<meta name="twitter:image" content="https://somework.github.io/dsx/demo.gif">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⌘</text></svg>">
<style>
:root {
--bg: oklch(15% 0.012 260);
--bg-2: oklch(18% 0.014 260);
--surface: oklch(21% 0.016 260);
--line: oklch(30% 0.02 260);
--text: oklch(94% 0.008 250);
--muted: oklch(70% 0.02 255);
--faint: oklch(56% 0.02 255);
/* green = dsx's own success output. Semantic, not decorative. */
--ok: oklch(80% 0.16 150);
--ok-dim: oklch(68% 0.12 150);
--link: oklch(82% 0.10 220);
--warn: oklch(84% 0.12 80);

--mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
--sans: system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;

--maxw: 1040px;
--r: 14px;
--ease: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--sans);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
/* faint atmospheric wash, top-left */
background-image:
radial-gradient(1200px 700px at 12% -8%, oklch(24% 0.03 250 / 0.55), transparent 60%),
radial-gradient(900px 600px at 110% 0%, oklch(22% 0.04 160 / 0.28), transparent 55%);
background-attachment: fixed;
}

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
section { padding: clamp(3.5rem, 2rem + 8vw, 7rem) 0; }
a { color: var(--link); text-decoration: none; transition: color .15s var(--ease); }
a:hover { color: var(--text); }
code { font-family: var(--mono); font-size: 0.92em; }

/* ---- top bar ---- */
header.bar {
position: sticky; top: 0; z-index: 10;
backdrop-filter: blur(10px);
background: oklch(15% 0.012 260 / 0.72);
border-bottom: 1px solid var(--line);
}
.bar .wrap { display: flex; align-items: center; gap: 20px; height: 60px; }
.brand { font-family: var(--mono); font-weight: 600; letter-spacing: .02em; font-size: 1.05rem; }
.brand b { color: var(--ok); }
.bar nav { margin-left: auto; display: flex; gap: 22px; font-size: .92rem; }
.bar nav a { color: var(--muted); }
.bar nav a:hover { color: var(--text); }
@media (max-width: 620px) { .bar nav .hide-sm { display: none; } }

/* ---- hero ---- */
.hero h1 {
font-size: clamp(2.6rem, 1rem + 8vw, 5.2rem);
line-height: 1.02;
letter-spacing: -0.03em;
margin: 0 0 1.1rem;
font-weight: 680;
}
.hero h1 .accent { color: var(--ok); }
.lede { font-size: clamp(1.05rem, 0.9rem + 0.8vw, 1.3rem); color: var(--muted); max-width: 46ch; margin: 0 0 2rem; }
.unofficial-inline { color: var(--warn); font-weight: 600; }

.cta { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-bottom: 2.6rem; }
.btn {
display: inline-flex; align-items: center; gap: 9px;
font-family: var(--mono); font-size: .95rem;
padding: 12px 18px; border-radius: 10px;
border: 1px solid var(--line);
background: var(--surface); color: var(--text);
transition: transform .18s var(--ease), border-color .18s var(--ease), background .18s var(--ease);
}
.btn:hover { transform: translateY(-2px); border-color: var(--ok-dim); color: var(--text); }
.btn.primary { background: linear-gradient(180deg, oklch(30% 0.06 155), oklch(24% 0.05 155)); border-color: var(--ok-dim); }
.btn.primary:hover { background: linear-gradient(180deg, oklch(34% 0.07 155), oklch(27% 0.06 155)); }
.btn .k { color: var(--faint); }

/* the number: struck cost vs one line */
.contrast {
display: grid; grid-template-columns: 1fr auto 1fr; gap: 18px; align-items: center;
margin: 0 0 2.4rem; max-width: 620px;
}
@media (max-width: 560px) { .contrast { grid-template-columns: 1fr; text-align: left; } .contrast .arrow { display:none; } }
.contrast .cell .n { font-family: var(--mono); font-size: clamp(1.4rem, 1rem + 2vw, 2.1rem); font-weight: 600; }
.contrast .before .n { color: var(--faint); text-decoration: line-through; text-decoration-color: oklch(60% 0.14 25 / .7); }
.contrast .after .n { color: var(--ok); }
.contrast .cell .cap { color: var(--muted); font-size: .82rem; margin-top: 2px; }
.contrast .arrow { color: var(--faint); font-size: 1.4rem; }

/* ---- terminal card ---- */
.term {
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r);
overflow: hidden;
box-shadow: 0 24px 60px -30px oklch(0% 0 0 / 0.8), 0 2px 0 oklch(100% 0 0 / 0.03) inset;
}
.term .chrome { display: flex; align-items: center; gap: 7px; padding: 11px 14px; border-bottom: 1px solid var(--line); background: var(--surface); }
.term .chrome i { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.term .chrome i:nth-child(1){ background:oklch(65% 0.16 25);} .term .chrome i:nth-child(2){ background:oklch(80% 0.13 85);} .term .chrome i:nth-child(3){ background:oklch(78% 0.15 150);}
.term .chrome span { margin-left: 8px; color: var(--faint); font-family: var(--mono); font-size: .8rem; }
.term pre { margin: 0; padding: 18px 20px; font-family: var(--mono); font-size: clamp(.8rem, .72rem + .4vw, .92rem); line-height: 1.7; overflow-x: auto; }
.term .p { color: var(--faint); } /* prompt */
.term .c { color: var(--text); } /* command */
.term .o { color: var(--muted); } /* output */
.term .ok { color: var(--ok); }

figure { margin: 2rem 0 0; }
figure img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--bg-2); }
figure figcaption { color: var(--faint); font-size: .84rem; margin-top: 10px; font-family: var(--mono); }

/* ---- section heads ---- */
.eyebrow { font-family: var(--mono); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ok-dim); margin: 0 0 .8rem; }
h2 { font-size: clamp(1.6rem, 1.1rem + 2.4vw, 2.4rem); letter-spacing: -0.02em; margin: 0 0 1rem; font-weight: 640; }
.section-lede { color: var(--muted); max-width: 60ch; margin: 0 0 2rem; }

/* ---- feature list (editorial, not uniform cards) ---- */
.safety { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
@media (max-width: 640px) { .safety { grid-template-columns: 1fr; } }
.safety .item { background: var(--bg); padding: 26px 24px; transition: background .2s var(--ease); }
.safety .item:hover { background: var(--bg-2); }
.safety .item h3 { margin: 0 0 .5rem; font-size: 1.05rem; font-family: var(--mono); color: var(--text); font-weight: 600; }
.safety .item h3 .m { color: var(--ok); }
.safety .item p { margin: 0; color: var(--muted); font-size: .95rem; }

/* ---- install ---- */
.install { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 680px) { .install { grid-template-columns: 1fr; } }
.card { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); padding: 22px; }
.card h3 { margin: 0 0 .3rem; font-size: 1.05rem; }
.card .sub { color: var(--faint); font-size: .84rem; margin: 0 0 14px; }
.cmd { position: relative; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 13px 15px; font-family: var(--mono); font-size: .85rem; overflow-x: auto; color: var(--text); }
.cmd .p { color: var(--ok-dim); user-select: none; }
.span-2 { grid-column: 1 / -1; }

/* ---- verbs ---- */
.verbs { display: flex; flex-wrap: wrap; gap: 9px; }
.verbs code { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 7px 12px; font-size: .88rem; color: var(--text); transition: border-color .15s var(--ease), transform .15s var(--ease); }
.verbs code:hover { border-color: var(--ok-dim); transform: translateY(-1px); }

/* ---- caveat ---- */
.caveat { border: 1px solid oklch(50% 0.10 80 / .5); background: oklch(22% 0.03 80 / .35); border-radius: var(--r); padding: 24px 26px; }
.caveat h2 { color: var(--warn); }
.caveat p { color: var(--muted); margin: 0; max-width: 68ch; }

/* ---- footer ---- */
footer { border-top: 1px solid var(--line); padding: 42px 0 64px; color: var(--faint); }
footer .cols { display: flex; flex-wrap: wrap; gap: 30px 40px; align-items: baseline; }
footer a { color: var(--muted); }
footer .meta { margin-left: auto; font-family: var(--mono); font-size: .82rem; text-align: right; }

::selection { background: oklch(80% 0.16 150 / .28); }
</style>
</head>
<body>

<header class="bar">
<div class="wrap">
<span class="brand"><b>dsx</b></span>
<nav>
<a href="#how">How it works</a>
<a href="#install">Install</a>
<a href="#safety" class="hide-sm">Safety</a>
<a href="https://github.com/somework/dsx">GitHub&nbsp;↗</a>
</nav>
</div>
</header>

<section class="hero">
<div class="wrap">
<h1>Sync a Claude Design project.<br><span class="accent">Zero bytes</span> through a model.</h1>
<p class="lede">
dsx moves files between a <a href="https://claude.ai/design">Claude Design</a> project and a
local directory directly — the file contents never pass through any model's context.
<span class="unofficial-inline">Unofficial</span>, single Go binary, stdlib only.
</p>

<div class="contrast">
<div class="cell before"><div class="n">~665,000</div><div class="cap">tokens — agents reading each file</div></div>
<div class="arrow">→</div>
<div class="cell after"><div class="n">1 line</div><div class="cap">the same pull, through dsx</div></div>
</div>

<div class="cta">
<a class="btn primary" href="#install"><span class="k">$</span> brew install somework/tap/dsx</a>
<a class="btn" href="https://github.com/somework/dsx">Source on GitHub</a>
</div>

<div class="term">
<div class="chrome"><i></i><i></i><i></i><span>~/design</span></div>
<pre><span class="p">$</span> <span class="c">dsx clone $PROJECT design</span>
<span class="ok">pulled 103, unchanged 0, binary 6 (660.1 KB)</span>
<span class="p">$</span> <span class="c">dsx status</span>
<span class="o">clean — nothing changed locally, nothing new on the server</span></pre>
</div>

<figure>
<img src="demo.gif" width="1440" height="560" alt="Terminal: dsx clone pulls a Design project in one summary line, then dsx status reports the tree is clean.">
<figcaption>A real run. One summary line replaces reading every file into context.</figcaption>
</figure>
</div>
</section>

<section id="how">
<div class="wrap">
<p class="eyebrow">How it works</p>
<h2>It's git for a Design project.</h2>
<p class="section-lede">
Familiar verbs, and everything else addressed as <code>dsx &lt;noun&gt; &lt;verb&gt;</code>.
Conflicts are decided on bytes, not clocks. It reads Claude Code's existing OAuth token —
no separate login, no MCP server to wire up. One-time: run <code>/design consent</code> in Claude Code.
</p>
<div class="verbs">
<code>clone</code><code>pull</code><code>push</code><code>status</code><code>fetch</code>
<code>diff</code><code>pin</code><code>unpin</code><code>dsx &lt;noun&gt; &lt;verb&gt;</code>
</div>

<figure>
<img src="roundtrip.gif" width="1440" height="560" alt="Terminal: edit a file and add a new one, dsx status shows modified and untracked, dsx diff shows the byte-level divergence, dsx push sends two files, dsx status is clean.">
<figcaption>The full round-trip — edit &amp; add, <b>status</b>, byte-level <b>diff</b>, <b>push</b>, clean.</figcaption>
</figure>
</div>
</section>

<section id="safety" class="alt">
<div class="wrap">
<p class="eyebrow">The other obsession</p>
<h2>Built not to lose your files.</h2>
<p class="section-lede">Not spending tokens is the first goal. Not losing data is the second, and it shows up everywhere.</p>
<div class="safety">
<div class="item">
<h3><span class="m">--prune</span> proves before it deletes</h3>
<p>Removes only files it can prove dsx pulled and you haven't touched. Untracked → not ours. Edited → a conflict, never a silent delete.</p>
</div>
<div class="item">
<h3>Conflicts on <span class="m">bytes</span></h3>
<p>Divergence is decided on content, not timestamps or etags. The both-sides-changed case is a conflict, full stop.</p>
</div>
<div class="item">
<h3>Atomic writes</h3>
<p>Every file lands temp-then-rename. A killed process never leaves a half-written file — and never a fragment the next run blames on you.</p>
</div>
<div class="item">
<h3>The token is <span class="m">read</span>, never printed</h3>
<p>dsx reads Claude Code's OAuth token, never writes, refreshes, or prints it — it won't even wrap it into an error string.</p>
</div>
</div>
</div>
</section>

<section id="install">
<div class="wrap">
<p class="eyebrow">Install</p>
<h2>One binary, no runtime.</h2>
<p class="section-lede">macOS and Linux, on both <code>amd64</code> and <code>arm64</code>. Nothing to configure.</p>
<div class="install">
<div class="card">
<h3>Homebrew — macOS</h3>
<p class="sub">Spell the tap out; Homebrew 6.0 needs the fully-qualified form to grant trust inline.</p>
<div class="cmd"><span class="p">$ </span>brew install somework/tap/dsx</div>
</div>
<div class="card">
<h3>go install</h3>
<p class="sub">If you'd rather build from source what you can read.</p>
<div class="cmd"><span class="p">$ </span>go install github.com/somework/dsx@latest</div>
</div>
<div class="card span-2">
<h3>Archive — macOS &amp; Linux, with provenance</h3>
<p class="sub">Release archives carry GitHub build attestations — verify before you unpack.</p>
<div class="cmd"><span class="p">$ </span>gh attestation verify dsx_*.tar.gz --repo somework/dsx</div>
</div>
</div>
</div>
</section>

<section>
<div class="wrap">
<div class="caveat">
<p class="eyebrow" style="color:var(--warn)">Read this first</p>
<h2>Unofficial, and honest about it.</h2>
<p>
The Claude Design endpoint is undocumented and makes no promises. dsx was built by probing
it and pinning every claim with a live test against the real server — but a server deploy can
still break it. It is not affiliated with or endorsed by Anthropic. The protocol notes, the
threat model, and the design decisions that were considered and declined are all in the repo:
<a href="https://github.com/somework/dsx/blob/main/PROTOCOL.md">PROTOCOL.md</a> ·
<a href="https://github.com/somework/dsx/blob/main/SECURITY.md">SECURITY.md</a>.
</p>
</div>
</div>
</section>

<footer>
<div class="wrap cols">
<a href="https://github.com/somework/dsx">GitHub</a>
<a href="https://github.com/somework/dsx/releases">Releases</a>
<a href="https://github.com/somework/dsx/blob/main/PROTOCOL.md">Protocol</a>
<a href="https://github.com/somework/dsx/blob/main/CHANGELOG.md">Changelog</a>
<a href="https://github.com/somework/dsx/blob/main/SECURITY.md">Security</a>
<span class="meta">MIT · single Go binary · stdlib only</span>
</div>
</footer>

</body>
</html>
Binary file added docs/roundtrip.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.