diff --git a/site/index.html b/site/index.html index 0257ae2..87b42f9 100644 --- a/site/index.html +++ b/site/index.html @@ -32,6 +32,7 @@ --green: #34d058; --purple: #b05cff; --cyan: #00d5f0; + --on-color: #15171a; --tint: 7%; } @media (prefers-color-scheme: dark) { @@ -118,7 +119,7 @@ h2 { padding: 0; list-style: none; } -.features li { +.features > li { --c: var(--blue); padding: 20px; border: 1px solid var(--border); @@ -152,15 +153,763 @@ h2 { .features .hero h3 { font-size: 22px; } -.features p { +.features summary p { margin: 0; color: var(--muted); font-size: 14px; } -.features .hero p { +.features .hero summary p { max-width: 52em; font-size: 16px; } +.features summary { + position: relative; + display: block; + padding-right: 32px; + cursor: pointer; + list-style: none; +} +.features summary::-webkit-details-marker { + display: none; +} +.more { + position: absolute; + top: 4px; + right: 4px; + width: 10px; + height: 10px; + border-right: 2px solid var(--muted); + border-bottom: 2px solid var(--muted); + transform: rotate(45deg); + transition: transform 250ms cubic-bezier(0.65, 0, 0.35, 1), border-color 150ms; +} +.features summary:hover .more { + border-color: var(--c); +} +details[open] .more { + transform: translateY(5px) rotate(225deg); +} +.features > li:has(details[open]) { + grid-column: 1 / -1; +} +::view-transition-group(*) { + overflow: hidden; + border-radius: 10px; + animation-duration: 300ms; + animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); +} +::view-transition-old(*), +::view-transition-new(*) { + height: 100%; + object-fit: none; + object-position: left top; +} +.detail { + margin-top: 24px; + padding-top: 24px; + border-top: 1px solid color-mix(in srgb, var(--c) 30%, var(--border)); +} +.points { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin: 28px 0 0; + padding: 0; + list-style: none; + color: var(--muted); + font-size: 14px; + text-wrap: pretty; +} +.points strong { + display: block; + margin-bottom: 4px; + color: var(--text); +} +.fig { + font-size: 13px; + line-height: 1.5; +} +.fig ul { + margin: 0; + padding: 0; + list-style: none; +} +.fig i { + display: inline-block; + flex: none; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--c); +} +.fig .live { + animation: pulse 1.6s ease-in-out infinite; +} +.fig b { + font-weight: 700; +} +.muted { + color: var(--muted); +} +.split { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + align-items: start; +} +.stack { + display: grid; + gap: 12px; +} +.win { + overflow: hidden; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--bg); +} +.bar { + display: flex; + align-items: center; + gap: 5px; + padding: 6px 10px; + border-bottom: 1px solid var(--border); + background: var(--surface); + color: var(--muted); + font-size: 12px; +} +.fig .bar i { + width: 7px; + height: 7px; + background: var(--border); +} +.bar i:last-of-type { + margin-right: 6px; +} +.body { + padding: 12px; +} +.row { + display: flex; + align-items: center; + gap: 10px; + padding: 6px 0; + border-top: 1px solid var(--border); +} +.row:first-child { + border-top: 0; +} +.row .end { + margin-left: auto; + color: var(--muted); +} +.chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 1px 8px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg); + font-size: 12px; + white-space: nowrap; +} +.chip.on { + border-color: var(--c); + background: color-mix(in srgb, var(--c) 14%, var(--bg)); +} +.btn { + display: inline-block; + padding: 4px 12px; + border-radius: 6px; + background: var(--c); + color: var(--on-color); + font-size: 12px; + font-weight: 700; + white-space: nowrap; +} +.btn.ghost { + border: 1px solid var(--border); + background: var(--bg); + color: var(--text); +} +.msg { + max-width: 88%; + margin-top: 8px; + padding: 8px 10px; + border-radius: 8px; + background: var(--surface); +} +.msg:first-child { + margin-top: 0; +} +.msg.you { + margin-left: auto; + background: color-mix(in srgb, var(--c) 16%, var(--bg)); +} +.msg .row { + padding: 3px 0; + border: 0; +} +.caption { + margin-top: 8px; + color: var(--muted); + font-size: 12px; + text-align: center; +} +.wires { + width: 100%; + height: 100%; + overflow: visible; +} +.wires path { + fill: none; + stroke: var(--c); + stroke-width: 2; + stroke-dasharray: 6 6; + vector-effect: non-scaling-stroke; + animation: flow 1s linear infinite; +} +.wires .off { + stroke: var(--border); + animation: none; +} +.diagram { + display: grid; + grid-template-columns: minmax(0, 5fr) minmax(48px, 2fr) minmax(0, 5fr); +} +.server { + align-self: center; + padding: 16px; + box-shadow: 0 0 0 4px color-mix(in srgb, var(--c) 18%, transparent); +} +.server .label { + display: flex; + justify-content: space-between; + margin-bottom: 6px; + font-weight: 700; +} +.server .label span { + color: var(--muted); + font-weight: 400; +} +.server .row:first-child { + border-top: 1px solid var(--border); +} +.server .red .end { + color: var(--text); + font-weight: 700; +} +.clients { + display: grid; + grid-template-rows: repeat(3, 1fr); + gap: 12px; +} +.client .rows { + display: flex; + align-items: center; + gap: 8px; + padding: 10px; + color: var(--muted); + font-size: 12px; +} +.rows span { + flex: 1; + height: 8px; + border-radius: 4px; + background: var(--c); +} +.client.asleep { + opacity: 0.45; +} +.servers .row.on { + margin: 0 -12px; + padding: 6px 12px; + background: color-mix(in srgb, var(--c) 12%, var(--bg)); +} +.projects { + padding: 4px 0 6px 18px; + color: var(--muted); +} +.projects li::before { + content: "└ "; + color: var(--border); +} +.synced .body { + display: flex; + flex-wrap: wrap; + gap: 6px; +} +.task .body { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 6px; +} +.task .name { + flex-basis: 100%; + font-weight: 700; +} +.option { + display: flex; + align-items: center; + gap: 10px; + margin-top: 8px; + padding: 8px 10px; + border: 1px solid var(--border); + border-radius: 8px; +} +.option::before { + content: ""; + flex: none; + width: 12px; + height: 12px; + border: 2px solid var(--border); + border-radius: 50%; +} +.option.on { + border-color: var(--c); + background: color-mix(in srgb, var(--c) 10%, var(--bg)); +} +.option.on::before { + border-color: var(--c); + background: radial-gradient(var(--c) 40%, transparent 45%); +} +.option > span { + margin-left: auto; +} +.notif { + display: flex; + gap: 12px; + padding: 14px; + border: 1px solid var(--border); + border-radius: 14px; + background: color-mix(in srgb, var(--surface) 80%, var(--bg)); + box-shadow: 0 6px 24px color-mix(in srgb, var(--text) 10%, transparent); +} +.notif .app { + flex: none; + width: 32px; + height: 32px; + border-radius: 8px; + background: linear-gradient(135deg, var(--red), var(--orange), var(--purple)); +} +.flow { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin-bottom: 16px; +} +.flow .arrow { + color: var(--muted); +} +.finding { + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: 6px 10px; + padding: 10px 0; + border-top: 1px solid var(--border); +} +.finding:first-child { + border-top: 0; +} +.finding .reply { + grid-column: 2 / -1; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + color: var(--muted); +} +.squash { + align-items: center; +} +.ready .body { + display: grid; + justify-items: start; + gap: 8px; +} +.graph svg { + display: block; + width: 100%; +} +.graph path { + fill: none; + stroke-width: 2; +} +.graph .line { + stroke: var(--border); +} +.graph .branch { + stroke: var(--c); + stroke-dasharray: 5 5; + animation: flow 1s linear infinite; +} +.graph .old { + fill: var(--border); +} +.graph .turn { + fill: var(--bg); + stroke: var(--muted); + stroke-width: 1.5; +} +.graph .new { + fill: var(--c); + stroke: color-mix(in srgb, var(--c) 30%, transparent); + stroke-width: 8; +} +.legend { + display: flex; + justify-content: space-between; + gap: 12px; + margin-top: 6px; + color: var(--muted); + font-size: 12px; +} +.legend b { + color: var(--text); +} +.timeline { + position: relative; + display: flex; + justify-content: space-between; + padding: 0 4%; +} +.timeline::before { + content: ""; + position: absolute; + top: 50%; + left: 4%; + right: 4%; + border-top: 2px solid var(--border); +} +.node { + position: relative; + display: grid; + place-items: center; + width: 36px; + height: 36px; + border: 2px solid var(--border); + border-radius: 50%; + background: var(--bg); + font-size: 12px; +} +.node.on { + border-color: var(--c); + background: color-mix(in srgb, var(--c) 18%, var(--bg)); + font-weight: 700; +} +.fork { + display: flex; + flex-direction: column; + align-items: center; +} +.fork::before { + content: ""; + height: 28px; + border-left: 2px dashed var(--c); +} +.fork .win { + width: min(100%, 380px); +} +.snaps .split { + align-items: center; +} +.diff .row { + font-variant-numeric: tabular-nums; +} +.plus { + color: var(--green); +} +.minus { + color: var(--red); +} +.pipeline { + display: grid; + grid-template-columns: minmax(0, 3fr) minmax(32px, 1fr) minmax(0, 3fr) minmax(32px, 1fr) minmax(0, 3fr); + align-items: stretch; +} +.pipeline .stack { + grid-template-rows: repeat(3, 1fr); +} +.stage { + align-self: center; + padding: 10px 12px; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--bg); +} +.pipeline .stack .stage { + align-self: stretch; +} +.stage .muted { + display: block; + font-size: 12px; +} +.screen { + position: relative; +} +.screen .body { + display: grid; + gap: 10px; +} +.screen .title { + line-height: 20px; +} +.field { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + height: 34px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: 6px; +} +.typed { + overflow: hidden; + white-space: nowrap; +} +.email { + width: 15ch; + animation: type-email 8s infinite; +} +.password { + width: 8ch; + animation: type-password 8s infinite; +} +.screen .btn { + justify-self: end; + height: 28px; + line-height: 20px; + animation: press 8s infinite; +} +.toast { + position: absolute; + left: 12px; + bottom: 12px; + display: flex; + align-items: center; + gap: 8px; + padding: 4px 10px; + border: 1px solid var(--c); + border-radius: 6px; + background: color-mix(in srgb, var(--c) 16%, var(--bg)); + font-size: 12px; + animation: toast 8s infinite; +} +.cursor { + position: absolute; + top: 170px; + left: calc(100% - 56px); + display: flex; + align-items: flex-start; + pointer-events: none; + animation: steer 8s infinite; +} +.cursor svg { + width: 18px; + height: 18px; + fill: var(--c); + stroke: var(--bg); + stroke-width: 1; +} +.cursor .tag { + margin: 14px 0 0 -2px; + padding: 0 6px; + border-radius: 4px; + background: var(--c); + color: var(--on-color); + font-size: 11px; + font-weight: 700; +} +.log .row:nth-child(1) { + animation: log-1 8s infinite; +} +.log .row:nth-child(2) { + animation: log-2 8s infinite; +} +.log .row:nth-child(3) { + animation: log-3 8s infinite; +} +.log .row:nth-child(4) { + animation: log-4 8s infinite; +} +@keyframes steer { + 0%, + 4% { + top: 200px; + left: 25%; + opacity: 0; + } + 12%, + 32% { + top: 84px; + left: 55%; + opacity: 1; + } + 40%, + 52% { + top: 128px; + left: 55%; + } + 60%, + 64% { + top: 170px; + left: calc(100% - 56px); + transform: none; + } + 62% { + transform: scale(0.85); + } + 92% { + opacity: 1; + } + 100% { + top: 170px; + left: calc(100% - 56px); + opacity: 0; + } +} +@keyframes type-email { + 0%, + 12% { + width: 0; + animation-timing-function: steps(15); + } + 30%, + 92% { + width: 15ch; + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes type-password { + 0%, + 40% { + width: 0; + animation-timing-function: steps(8); + } + 50%, + 92% { + width: 8ch; + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes press { + 0%, + 61%, + 64%, + 100% { + transform: none; + } + 62% { + transform: scale(0.92); + } +} +@keyframes toast { + 0%, + 64% { + opacity: 0; + transform: translateY(6px); + } + 68%, + 92% { + opacity: 1; + transform: none; + } + 100% { + opacity: 0; + } +} +@keyframes log-1 { + 0%, + 6% { + opacity: 0; + } + 8%, + 92% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes log-2 { + 0%, + 30% { + opacity: 0; + } + 32%, + 92% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes log-3 { + 0%, + 50% { + opacity: 0; + } + 52%, + 92% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes log-4 { + 0%, + 66% { + opacity: 0; + } + 68%, + 92% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes pulse { + 50% { + opacity: 0.3; + } +} +@keyframes flow { + to { + stroke-dashoffset: -12; + } +} +@media (prefers-reduced-motion: reduce) { + .fig .live, + .wires path, + .graph .branch, + .typed, + .screen .btn, + .toast, + .cursor, + .log .row { + animation: none; + } + .more { + transition: none; + } + ::view-transition-group(*), + ::view-transition-old(*), + ::view-transition-new(*) { + animation: none; + } +} .features .red { --c: var(--red); } @@ -176,6 +925,9 @@ h2 { .features .purple { --c: var(--purple); } +.features .blue { + --c: var(--blue); +} @media (max-width: 900px) { .features { grid-template-columns: repeat(2, 1fr); @@ -194,6 +946,30 @@ h2 { .features .wide { grid-column: auto; } + .split, + .diagram, + .pipeline { + grid-template-columns: 1fr; + gap: 16px; + } + .wires { + display: none; + } + .clients { + grid-template-rows: none; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + } + .client .bar i { + display: none; + } + .pipeline .stack { + grid-template-rows: none; + } + .points { + grid-template-columns: 1fr; + gap: 14px; + } } ol { margin: 0; @@ -227,16 +1003,309 @@ footer {
The agents run on one Mac that stays on, such as a Mac mini in a closet. Open byre on your laptop, your desk Mac, or all of them at once: each shows the same tasks, questions and transcripts live. Close the laptop and the agents keep working.
Your servers sync through iCloud, so a new Mac finds them on first launch. Switch between servers in one window, each with as many projects as you like and its own colour.
Every task gets its own git worktree, branch and port block. Talk to its agent in a live transcript, even mid-turn.
One long-running agent watches every task, points you at what needs you, and starts, messages, merges or discards tasks when you ask.
When an agent needs a decision, it lays out the options and recommends one. Pick an answer in the inbox or right from the notification, and the agent carries on.
Every turn that changes files is reviewed by the other vendor's model. The agent fixes the findings it agrees with on its own and says why it skips the rest; you can overrule any of them with a click.
The agent merges main in and resolves conflicts, then byre squashes, pushes and closes the task.
Step through a task's snapshots, diff any of them, and fork a new task from any one, conversation included.
Agents spawn subtasks or share a worktree as a team. Workflows chain stages with fan-out and fan-in.
Agents can see and drive the Mac byre runs on, and the Macs you have the app open on, when a task needs it.
The agents run on one Mac that stays on, such as a Mac mini in a closet. Open byre on your laptop, your desk Mac, or all of them at once: each shows the same tasks, questions and transcripts live. Close the laptop and the agents keep working.
Your servers sync through iCloud, so a new Mac finds them on first launch. Switch between servers in one window, each with as many projects as you like and its own color.
Every task gets its own git worktree, branch and port block. Talk to its agent in a live transcript, even mid-turn.
One long-running agent watches every task, points you at what needs you, and starts, messages, merges or discards tasks when you ask.
When an agent needs a decision, it lays out the options and recommends one. A notification brings you straight to it; pick an answer and the agent carries on.
Every turn that changes files is reviewed by the other vendor's model. The agent fixes the findings it agrees with on its own and says why it skips the rest; you can overrule any of them with a click.
The agent merges main in and resolves conflicts, then byre squashes, pushes and closes the task.
Step through a task's snapshots, diff any of them, and fork a new task from any one, conversation included.
Agents spawn subtasks or share a worktree as a team. Workflows chain stages with fan-out and fan-in.
Agents can see and drive the Mac byre runs on, and the Macs you have the app open on, when a task needs it.