Watch
0
0
Fork
You've already forked hyperhive
0

swarm ui: the start page ends with the slug, its gradients animated

hyperhive / we are the wired between two shaded gradients that pulse in a
wave, still under reduced motion. It sits under 2em from the bottom edge,
clear of the setup assistant.
This commit is contained in:
iris 2026-11-01 13:31:34 +01:00 • committed by mara
commit 0e840bd34b
5 changed files with 94 additions and 11 deletions

View file

@ -20,16 +20,16 @@ the highlighted one. **Escape**, **Tab** or a press elsewhere shut the list with
changing anything. Typing the start of an option's name picks it, also with the list changing anything. Typing the start of an option's name picks it, also with the list
shut. A dropdown inside a dialog opens above the dialog and the dialog doesn't cut it off. shut. A dropdown inside a dialog opens above the dialog and the dialog doesn't cut it off.
| route | what | | route | what |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/` | the start page: the swarm's name over a digital-rain backdrop, plus a paperclip offering to set up an agent while no `ruth` exists, or her hive declares her destroyed (it opens the create form with `ruth` filled in); the swarm name in the header links here | | `/` | the start page: the swarm's name over a digital-rain backdrop with the slug (`hyperhive / we are the wired`, its shaded gradients pulsing in a wave unless reduced motion is on) at the foot, plus a paperclip offering to set up an agent while no `ruth` exists, or her hive declares her destroyed (it opens the create form with `ruth` filled in); the swarm name in the header links here |
| `/agents` | every agent as a card that opens in place (status, config PR, wanted state, inference settings, resource caps, permissions, accounts, terminal), under a folded **hives** card with the hive directory and each hive's last reported status; create agents (with their permissions, optionally from an [archetype](archetypes.md)), link forge, matrix and GitHub accounts | | `/agents` | every agent as a card that opens in place (status, config PR, wanted state, inference settings, resource caps, permissions, accounts, terminal), under a folded **hives** card with the hive directory and each hive's last reported status; create agents (with their permissions, optionally from an [archetype](archetypes.md)), link forge, matrix and GitHub accounts |
| `/agents/<name>/terminal` | one agent's live terminal | | `/agents/<name>/terminal` | one agent's live terminal |
| `/agents/<name>/subagents/<subagent>/terminal` | one of that agent's subagents' live terminal | | `/agents/<name>/subagents/<subagent>/terminal` | one of that agent's subagents' live terminal |
| `/reports` | two folded cards, each read only once opened: the **alerts** the swarm's Grafana holds now, the firing ones, with a button for the pending, no-data and error ones and a link to Grafana's own alert list; read through the controller with a Viewer service-account token, and a cross-repo **issue report** | | `/reports` | two folded cards, each read only once opened: the **alerts** the swarm's Grafana holds now, the firing ones, with a button for the pending, no-data and error ones and a link to Grafana's own alert list; read through the controller with a Viewer service-account token, and a cross-repo **issue report** |
| `/jobs` | the controller's job graph, where agent creation and credential mints show progress, and under it the swarm builder's recent builds (agent config PRs, and agents built from `internal/meta` before a deploy), with what nix printed when one failed, and the review classifier's recent runs, a try-out on a real PR, and its settings | | `/jobs` | the controller's job graph, where agent creation and credential mints show progress, and under it the swarm builder's recent builds (agent config PRs, and agents built from `internal/meta` before a deploy), with what nix printed when one failed, and the review classifier's recent runs, a try-out on a real PR, and its settings |
| `/messages` | the swarm-wide message feed: every message between agents, and to them from the operator, reminders and compaction, with a history window and a filter on sender or recipient; a folded **broadcast** card above the feed sends one message to more than one agent at once, and a folded **schedules** card holds the scheduled prompts: add, edit, pause, resume and remove | | `/messages` | the swarm-wide message feed: every message between agents, and to them from the operator, reminders and compaction, with a history window and a filter on sender or recipient; a folded **broadcast** card above the feed sends one message to more than one agent at once, and a folded **schedules** card holds the scheduled prompts: add, edit, pause, resume and remove |
| `/notifications` | the notification router's flows: a switch for each built-in, every flow drawn as a graph, and an editor for custom flows | | `/notifications` | the notification router's flows: a switch for each built-in, every flow drawn as a graph, and an editor for custom flows |
Everything it shows comes from [`swarm-controller`](../../swarm-controller/README.md). Everything it shows comes from [`swarm-controller`](../../swarm-controller/README.md).
Pages that refresh on a timer share one polling rule: the page sends no new Pages that refresh on a timer share one polling rule: the page sends no new

View file

@ -21,3 +21,11 @@
0 0 0.4em color-mix(in srgb, var(--purple) 55%, transparent), 0 0 0.4em color-mix(in srgb, var(--purple) 55%, transparent),
0 0 1.2em var(--bg); 0 0 1.2em var(--bg);
} }
/* The slug sits at the foot of the page, over the rain. It stays under 2em
* from the bottom edge, where the setup assistant starts (bottom-right,
* `SetupAssistant.css`), so the two never overlap, however narrow the window. */
.start-page .ui-slug {
position: absolute;
inset: auto 0 0;
margin: 0 0 0.4em;
}

View file

@ -1,7 +1,8 @@
// <StartPage> — `/`, the swarm's landing page: the swarm's name over the // <StartPage> — `/`, the swarm's landing page: the swarm's name over the
// digital-rain backdrop, plus the setup assistant while the swarm has no // digital-rain backdrop, plus the setup assistant while the swarm has no
// `ruth`. The header's swarm name links here. The hive roster is a card on the agents page. // `ruth`, and the slug at the foot. The header's swarm name links here. The hive roster is a card on the agents page.
import { MatrixRain } from "../shell/MatrixRain.js"; import { MatrixRain } from "../shell/MatrixRain.js";
import { Slug } from "../ui/slug/Slug.js";
import { useSwarmName } from "../shell/useSwarmName.js"; import { useSwarmName } from "../shell/useSwarmName.js";
import { SetupAssistant } from "./SetupAssistant.js"; import { SetupAssistant } from "./SetupAssistant.js";
import "./StartPage.css"; import "./StartPage.css";
@ -17,6 +18,7 @@ export function StartPage() {
<MatrixRain /> <MatrixRain />
<h1 class="start-page-name">{name}</h1> <h1 class="start-page-name">{name}</h1>
<SetupAssistant /> <SetupAssistant />
<Slug />
</div> </div>
); );
} }

View file

@ -0,0 +1,43 @@
/* The slug: the signature line at the foot of a page. The shaded blocks pulse
in a wave, each glyph delayed by its index (`--i`). Motion is gated the way
`shell/Shell.css` gates its own: stilled under the OS preference and the
`data-motion` override, back on with `allow`. */
.ui-slug {
display: flex;
align-items: center;
justify-content: center;
gap: 1em;
margin: 2em 0 1em;
color: var(--purple-dim);
font-size: 0.8em;
letter-spacing: 0.15em;
}
.ui-slug-gradient {
white-space: pre;
}
.ui-slug-glyph {
display: inline-block;
animation: ui-slug-wave 2.4s ease-in-out infinite;
animation-delay: calc(var(--i) * 0.18s);
}
@keyframes ui-slug-wave {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.ui-slug-glyph {
animation: none;
}
}
:root[data-motion="reduce"] .ui-slug-glyph {
animation: none;
}
:root[data-motion="allow"] .ui-slug-glyph {
animation: ui-slug-wave 2.4s ease-in-out infinite;
animation-delay: calc(var(--i) * 0.18s);
}

View file

@ -0,0 +1,30 @@
// <Slug> — the signature line, `░▒▓█▓▒░ hyperhive / we are the wired ░▒▓█▓▒░`,
// the hive dashboard's footer line without its hive-c0re part. The
// shaded blocks at each end are the gradients: each glyph pulses a beat after
// its neighbour, so a wave runs along them (stilled under reduced motion, see
// `Slug.css`).
import "./Slug.css";
const GRADIENT = ["░", "▒", "▓", "█", "▓", "▒", "░"];
function Gradient() {
return (
<span class="ui-slug-gradient" aria-hidden="true">
{GRADIENT.map((glyph, i) => (
<span key={i} class="ui-slug-glyph" style={{ "--i": i }}>
{glyph}
</span>
))}
</span>
);
}
export function Slug() {
return (
<p class="ui-slug">
<Gradient />
<span class="ui-slug-text">hyperhive / we are the wired</span>
<Gradient />
</p>
);
}