← Learn · Build · 7 November 2026 · 7 min

Agent Crews: 48 Cursors, a Queue and a Crew for Every Block

My page that builds itself, scaled up: 48 named agent cursors wait in a queue, every block gets a crew, the headline is carried in letter by letter and a reviewer sends work back. Code and prompt inside.

The output, liveavivashishta.com/lab/agent-crews
Open the live page ↗

Agents at work was a page that twelve named cursors build in front of you. People liked it, and the most common reply was "more cursors". So I made the sequel: forty-eight of them, and instead of one cursor per block, every block gets a crew. It is live at avivashishta.com/lab/agent-crews.

The short version: idle cursors wait in a queue along the bottom of your screen. Each block takes a crew from the front of it: a marker drags the marquee and locks the block, a maker types, counts or carries the content in, a painter fills the cards in pixels, and a reviewer can flag a finished block in red until the maker fixes it. The headline arrives as a pile of letter tiles that eleven cursors carry to their slots at once. Everything is still real HTML, so the page is complete without JavaScript.

Step 1: six directions on a design canvas

Before writing code I asked Claude for designs, two or three ways to make the swarm cooler with more cursors doing something, plus a few ideas for using the same agents on other kinds of screens. It came back with six frames on one design canvas, each a still from the middle of a build:

  1. Crews. Every block gets a team with a job each. This page.
  2. Spawn tree. Claude splits into four leads, they split into sixteen, then sixty-four, and the smallest ones land on blocks.
  3. Flock. Two hundred tiny cursors spell the name, then stream off to build.
  4. Terminal. My stats as a stock ticker, with analyst cursors annotating the chart.
  5. Sheet. A spreadsheet portfolio the agents fill in. That became the agent sheet.
  6. Ship board. The Lab as a kanban, cards dragged from Building to Shipped.

I picked Crews because it answers "more cursors" without turning into noise: forty-eight cursors are fine to watch when each one is visibly doing a job.

Step 2: the queue

Twelve cursors flocking around the work looks lively. Forty-eight flocking looks like a swarm of flies. So idle cursors don't flock any more. They wait in a queue, a rank along the bottom of the screen, tags hidden and slightly faded, and close up the gaps as cursors leave.

const slot = (k: number) => {
  const perRow = Math.max(6, Math.floor((innerWidth - 420) / 26));
  return { x: 20 + (k % perRow) * 26, y: scrollY + innerHeight - 40 - Math.floor(k / perRow) * 28 };
};
// In the rAF loop, an idle cursor eases toward its place in the queue.
const s = slot(free.indexOf(a));
a.x += (s.x - a.x) * .09; a.y += (s.y - a.y) * .09;

The queue is an array. Taking a crew splices from the front, and a cursor that finishes goes back on the end. Because the slot is just its index, the whole rank shuffles along on its own every time someone leaves or comes back. The log in the corner shows three numbers: working, in the queue, and crews.

Step 3: a crew per block

In the first version a section shared its blocks round robin between a few cursors. Now every block in a section starts at once and asks the queue for a crew. If not enough cursors are free, it waits.

async function take(id: number, n: number, prefer?: string[]) {
  while (alive(id) && free.length < n) await sleep(60);
  const out: Agent[] = [];
  for (const name of prefer ?? []) { /* reviewers ask for QA, Proof, Lint or Test first */ }
  while (out.length < n) { const a = free[0]; pull(a); out.push(a); }
  return out;
}

A crew is two cursors, or three on a card that gets painted:

  • The marker flies to the top left corner and drags the dashed marquee with its live size label, the same as before. When it lets go, a small badge appears above the block: locked by Grid. Then it steps aside and goes back to the queue straight away, so the queue keeps moving.
  • The maker waits at the block's top right corner while the marker drags, then moves in and makes the thing: types the headline, counts up the number or carries the content in.
  • The painter waits below the card and then sweeps across it in three passes while the pixels fill from the bottom up, so the colour looks like it comes from the cursor.

Step 4: carrying the headline in

This is the moment I wanted from the first page. The headline is rendered as one span per letter, with each word kept in a nowrap span so it still wraps like normal text:

text.split(" ").map((w) => (
  <span className={styles.word}>{[...w].map((ch) => <span data-l>{ch}</span>)}</span>
))

With JavaScript and motion, each letter is invisible until it has been carried in. When the headline's crew gets to it, a pile of tiles appears on the right of the screen: each tile is the letter on a white card, in the headline's own font and size (read from getComputedStyle), shrunk and tilted at random. Eleven more cursors are taken from the queue. Each one walks to a tile, picks it up (it straightens and grows to full size), and carries it to the slot of its letter. The tile is moved with the cursor by the same callback the marquee uses:

await moveTo(a, r.x + gx, r.y + gy, undefined, (x, y) => {
  tile.style.translate = `${x - gx}px ${y - gy}px`;
});
letter.dataset.on = ""; tile.remove();

The grip point gx, gy is near the letter's bottom right, so the cursor looks like it's holding the tile by its corner. Using the translate property, not transform, means the tile's own rotate and scale can animate with a CSS transition at the same time. When it lands, the real letter appears in blue for a moment and settles to ink.

Step 5: a card carried in from off screen

One card, Make, isn't built where it is. Its content is moved off the right edge of the screen, and the marker and the maker carry it in between them, one cursor on each corner, the card tilted a few degrees and straightening as it arrives. The shadow under it is a "lifted" one while it's in transit.

Step 6: the reviewer

A block with a data-qa note gets a review after it's done. A cursor from the reviewer group (QA, Proof, Lint, Test) comes over, the block gets a red outline, and a note appears: "Corner radius is 16 here, 20 everywhere else. Sent back." The maker comes back to it, and after a beat the note changes to Fixed. Approved. and the outline turns blue and fades. It's staged, of course, but it's the part that makes it read as a team and not a screensaver: someone checks the work.

The small things

  • The counters in the header (agents, crews at work, actions) are live. An action is any visible step: a marquee, a lock, a letter landing, a paint pass.
  • Everything that worked on agents at work still does: the camera follows the work, a deliberate scroll hands over to you, ?play never hands over (/lab/agent-crews?play), Skip and Rebuild.
  • On phones there are eighteen cursors, five carriers for the headline, and the queue sits above the log.
  • With reduced motion or without JavaScript nothing is hidden and no cursor appears.

Build your own

Build a page that 48 named agent cursors build live, in React with CSS modules. Every block is real server-rendered HTML marked data-block with one child .fill, going through empty, mark (a dashed blue marquee dragged corner to corner with a live "W x H" label), rough (a solid outline with corner handles, a grey skeleton and a tooltip with its line of JSX) and done. Hide unbuilt blocks only under @media (scripting: enabled) and (prefers-reduced-motion: no-preference).

Idle cursors wait in a queue: a rank along the bottom of the viewport, tags hidden, each easing to the slot of its index in a free array, so the rank closes up when cursors leave. Every block in a section starts at once and takes a crew from the front of the queue (waiting if too few are free): a marker drags the marquee, shows a "locked by NAME" badge, then returns to the queue; a maker types the text, counts up numbers or carries the content in; a painter sweeps three passes over cards while a pixel grid fills from the bottom. Blocks with a data-qa note get a reviewer who outlines them in red with the note, the maker returns, and the note changes to "Fixed. Approved."

Render the headline as one span per letter inside nowrap word spans. To build it, spawn letter tiles (the letter on a white card in the headline's computed font, scaled to 0.6 and randomly rotated) on the right of the screen, take up to eleven extra carriers from the queue, and have each carry tiles to their letters' positions, moving the tile with the cursor via the CSS translate property while rotate and scale transition to 0 and 1. Carry one card in from off screen with two cursors on its corners. Keep one requestAnimationFrame loop, live counters for crews and actions, a log with working and queued counts, Skip, Rebuild and ?play.