Skip to content

feat: the bot's cursor follows each part of a screen as it is written - #37

Merged
httpsphl merged 2 commits into
mainfrom
feat/screen-cursor
Sep 29, 2026
Merged

httpsphl merged 2 commits into
mainfrom
feat/screen-cursor

Conversation

@httpsphl

Copy link
Copy Markdown
Owner

What

A cursor in the design area, in the spirit of Google Stitch: while a bot writes an HTML screen, its cursor follows each part being built, and the artboard scrolls along with it.

Daemon (spec 22.3)

  • Every draft served at /view starts with a small script. It goes after the doctype so the page keeps its layout mode, or at the top when there is no doctype. The file on disk is served as it is.
  • When the page is read, and again on load, the script:
    • finds where the content ends: the newest text, or the newest element;
    • scrolls so that spot stays in view;
    • posts {botloft: "cursor", view, point, box} to the app.
  • It waits for resize when the frame does not know its size yet. A cross-origin iframe can read the page with innerHeight 0, which was seen in the real test.

App (spec 22.5)

  • The cursor is the browser's own, now shared as BotCursor: the arrow in the bot's color with its name and the typing dots.
  • It glides to the point, and a frame in the bot's color marks the part being built. This works on the artboard and on the screen in focus.
  • Only the frame on show counts, because the version loading behind posts before it is swapped in. Measures are scaled by the view the script saw, since the preview's CSS zoom widens the iframe's view.
  • While only styles exist, the cursor waits at the top. Near the right or bottom edge, its name moves aside.
  • The preview's drafts import the daemon's cursor.js. Vite serves that one folder outside the app, only in dev.

Security (spec 22.6)

  • The script runs in the same sandbox as the page and only posts numbers.
  • The app accepts the message only from its own iframes, reads finite numbers only and clamps them to the page.

Tests

  • Rust: cargo test (256 tests), clippy and fmt pass.
    • Unit tests for where the script goes (doctype, BOM, a doctype still being written).
    • The screens integration test checks that the draft carries the script and the file does not.
  • App: pnpm check (144 tests) passes.
    • New cursor.test.tsx: the cursor scales to the artboard, parks while there is no point, shows the next version's mark only once it is on show, ignores other windows and hides when writing ends.
    • Unit tests for reading marks: clamping, the zoomed view, and messages that are not marks.
  • Real Claude Code (2.1.284, Haiku, Manual mode), with the app captured in headless Edge:
    • Four pages written live. The cursor followed the title, each card, each plan item and each table row, and the artboard scrolled along.
    • Page content never reached the daemon log.

Manual step

  • pnpm tauri dev with a dev BOTLOFT_HOME: ask a bot for a page and watch the cursor in the WebView2 window.

Each draft served at /view gets a small script first, after the doctype
so the page keeps its layout mode. Once the page is read it finds where
the content ends (the newest text, or the newest element), scrolls so
that spot stays in view, and posts the point, the part around it and the
view size it measured in to the app. A frame from another origin may read
the page before it knows its size, so the script waits for the resize.
The file on disk is served untouched.

Spec 22.3, 22.5, 22.6 and T3; tested with the real Claude Code.
…itten

While a bot writes a screen, its cursor (the arrow in its color with its
name, shared with the browser as BotCursor) glides to the end of what is
written, and a frame in its color marks the part being built, on the
artboard and on the screen in focus. Only the frame on show counts, so
the cursor matches what is seen; measures are scaled by the view the
script saw. With nothing visible yet the cursor waits at the top; near
the right or bottom edge its name moves aside. The preview's drafts use
the daemon's own script, and it writes at a pace closer to a model's.
@httpsphl
httpsphl merged commit d751359 into main Sep 29, 2026
3 checks passed
@httpsphl httpsphl mentioned this pull request Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant