Spectra
Primary cross-platform capture tool for screenshots, usage sequences, smart framing, and demo assets.
Install
claude plugin marketplace add tyroneross/RossLabs-AI-Toolkit
claude plugin install spectra@rosslabs-ai-toolkit
The Problem
Marketing captures span platforms that each demand their own stack: Chrome DevTools for web, Accessibility for macOS, simctl for iOS, and simulator workflows for watchOS. Stitching together screenshots, short clips, usage sequences, and exports across all of them is manual work that does not scale.
What I Built
Spectra is the primary Ross Labs capture tool for product demos: screenshots, guided usage sequences, smart framing, and a tagged export library across web, macOS, iOS, and watchOS. Video capture is supported where available and expanding.
Architecture
Spectra is an MCP server plus a local daemon — it exposes UI automation and capture as tools a host agent calls, rather than running its own planning loop. The primary path is host-routed: Claude Code, Codex, or another MCP-speaking coding agent reads a snapshot, decides the next action, and calls Spectra’s tools to execute it. Spectra.app, a standalone macOS menu-bar fallback, only plans locally (via Claude Haiku) when no host agent is present.
flowchart LR
H["Host agent (Claude Code / Codex)<br/>plans from spectra_snapshot"] -->|MCP tool calls| D
SA["Spectra.app standalone<br/>WalkthroughPlanner + Claude Haiku 4.5"] -.fallback, no host agent.-> D
D["spectra_connect<br/>driver select"] --> CDP["CdpDriver (web)"]
D --> NAT["NativeDriver (macOS AX)"]
D --> SIM["SimDriver (iOS / watchOS)"]
CDP --> SNAP["spectra_snapshot<br/>AX / DOM tree"]
NAT --> SNAP
SIM --> SNAP
SNAP -.AX empty or thin.-> VIS["Vision fallback<br/>Apple Vision framework, on-device"]
VIS --> STEP
SNAP --> STEP["spectra_step<br/>Jaro-Winkler resolve engine"]
STEP --> ACT["spectra_act<br/>driver executes"]
SNAP --> AN["spectra_analyze<br/>6-factor importance scoring"]
AN --> CAP["spectra_capture<br/>clean + auto-frame"]
ACT --> CAP
CAP --> LIB[("Library<br/>.spectra/library/index.json + media/")]
CAP --> DEMO["spectra_demo<br/>ffmpeg spotlight + captions"]
DEMO --> LIB
Models — which, where, why:
| Stage | Model / tier | Where it runs | Why there |
|---|---|---|---|
| Host-routed planning (primary path) | None — the host LLM (Claude Code, Codex, or another MCP-speaking coding agent) plans | Outside Spectra; the host reads spectra_snapshot output and calls Spectra’s MCP tools | Keeps Spectra a pure automation/capture layer — no API key, no model cost, no planning logic duplicated inside the tool for the path almost all sessions use |
| Standalone fallback planning | Claude Haiku 4.5 (default, overridable per call) | WalkthroughPlanner.swift + AnthropicClient.swift, Spectra.app only, one non-streaming call per turn | Small, fast model for single-turn action-plan JSON when no host agent is driving; temperature 0 for deterministic plans; the user’s own API key lives in Keychain and never reaches the daemon |
| Element-grounding fallback | Apple Vision framework (on-device, no network call) | computer-use/vision-fallback.ts, gated on AX-node-count (fires only when the AX tree is empty or thin) | AX reads take ~30–80ms and come pre-labeled; screenshot-grounding is ~5–50x slower and, per the code’s own cited benchmark, under 70% accurate on ScreenSpot-Pro — so vision is a fallback, never the default |
| Natural-language element resolution | Jaro-Winkler string similarity — deterministic, no model | core/resolve.ts, backs spectra_step | Matching “click the Log In button” to an AX label is a string-similarity problem, not a reasoning problem; resolving it without a model call keeps it instant and free |
| Screen importance scoring | 6-factor weighted heuristic (fixed weights, derived from UEyes CHI 2023 eye-tracking research) | spectra_analyze | Role, position, interactivity, label quality, density, and prominence combine into a fixed formula — reproducible scoring with no inference cost |
| Change / scene detection | dHash perceptual hash + AX structural diff — deterministic | intelligence/change.ts, spectra_demo action=scan | A binary “did the screen change” signal doesn’t need a model; a gradient hash and a tree diff answer it directly |
Models: minimal by design. Spectra runs model-free for its default host-routed usage; the one LLM in the stack (Claude Haiku 4.5) only activates in the standalone-app fallback path, and even the vision-grounding fallback is a local Apple framework, not a hosted model.
Tools & infra — which, why:
- MCP server (
@modelcontextprotocol/sdk) — exposes 15 tool handlers (connect,snapshot,step,act,capture,demo,analyze,discover,session,library,llm-step,record,walkthrough,replay,computer-use) over stdio to any MCP-speaking host. - Node.js daemon (
node:http, custom JSON envelope insrc/contract/wire.ts) — a long-running process holding driver connections and sessions, reachable over a Unix domain socket by default or optional loopback TCP with bearer-token auth, so the CLI/MCP process and the daemon can run as separate PIDs. CdpDriver— a hand-rolled Chrome DevTools Protocol client (own connection handling plus 7 domain wrappers), not Puppeteer or Playwright — keeps the web driver dependency-light for a narrow automation surface.NativeDriver/SimDriver— a Swift binary (spectra-native, built viaswiftcagainst Foundation, ApplicationServices, AppKit, CoreGraphics, Vision, ScreenCaptureKit, AVFoundation) bridging the macOS Accessibility API andsimctlfor iOS/watchOS.- FFmpeg — external binary, resolved via
which ffmpegrather than bundled — handles transcode, spotlight-focus rendering, lower-third caption burn-in, and scene-change scanning insidespectra_demo. - Zero-dependency PNG codec built on
node:zlib— decode/encode/crop/resize without pulling insharporjimp. - Storage — no database. A flat
.spectra/directory per project (found by walking up to.git,package.json, or an existing.spectra, else~/.spectra) holdssessions/<id>/for ephemeral step recordings andlibrary/index.json+library/media/<capture-id>/for the persistent tagged catalog; index writes are atomic (tmp file + rename). - ScreenCaptureKit + AVFoundation (Swift,
spectra-composite-capturebinary) — native screen recording with hardware H.264/HEVC encoding. - Next.js dashboard (
web-ui/) — local-only browse/manage/export UI served at:4300, separate from the MCP/daemon runtime. - Vitest — 30 test files, 329 tests per the repo’s own README, run via
npm test.
How it works
- A host agent (or
Spectra.appstandalone) callsspectra_connectwith a target — a URL, an app name, orsim:device— which selects a driver:CdpDriverfor web,NativeDriverfor macOS,SimDriverfor iOS/watchOS. spectra_snapshotreturns the current accessibility tree: a compact element list with roles, labels, bounds, and available actions. If the AX tree comes back empty or thin, the Apple Vision on-device fallback grounds the screen from pixels instead and returns AX-shaped nodes so the rest of the pipeline doesn’t need to know which source produced them.- In the host-routed path, the host LLM reads that snapshot and decides the next action itself, then calls
spectra_actorspectra_stepdirectly — no model runs inside Spectra for this step. In the standalone-app path,WalkthroughPlannersends the snapshot (plus an optional screenshot) to Claude Haiku 4.5 and parses the returned action plan. spectra_steptakes a natural-language intent (“click the Log In button”) and resolves it to a specific element with the Jaro-Winkler string-similarity engine, returning a confidence score alongside the resolved element ID.spectra_actexecutes the resolved action (click, type, clear, select, scroll, hover, focus) on the driver and returns the updated snapshot.spectra_analyzescores every element on screen with the 6-factor importance heuristic and groups them into labeled regions (Navigation, Form, etc.), also classifying overall UI state (loading, error, empty, populated).spectra_capturetakes the screenshot or recording. Visual cleanup (hide scrollbars, clean the simulator status bar, strip cursor artifacts) runs first if requested, then framing —full,element,region, orauto— crops to the relevant content using the importance scores from step 6.spectra_discoverautomates steps 2–7 across an entire app: BFS-crawls navigable elements, captures and frames each new screen, deduplicates by role+label fingerprint, and flags (without capturing) any screen showing password or credential fields.spectra_demoturns a raw recording into a polished clip:scanruns dHash-based scene-change analysis to find active segments,polish-clip/polish-scriptapply spotlight focus and burn in numbered lower-third captions via FFmpeg, andrun-scriptcan drive a live CDP browser through scripted beats while capturing.- Finished captures land in
.spectra/sessions/<id>/(ephemeral) or get promoted into.spectra/library/(persistent, tagged) viaspectra_library action=add— a flat JSON index plus amedia/<capture-id>/file, no database involved.
Tech stack
Node.js + TypeScript for the MCP server, daemon, and drivers; Swift for the native macOS/iOS/watchOS bridge (Accessibility API, simctl, ScreenCaptureKit, Apple Vision framework). The web driver is a hand-rolled Chrome DevTools Protocol client, not Puppeteer/Playwright. Element resolution (Jaro-Winkler), importance scoring, and change detection are all deterministic algorithms — no model in the loop. The one LLM in the stack, Claude Haiku 4.5, runs only in the standalone Spectra.app fallback planner when no host agent is present. FFmpeg (external binary) handles video transcode and demo-clip production. Storage is a flat .spectra/ directory — JSON index + media files, no database. A Next.js dashboard serves a local browse/export UI.
Impact
Spectra supersedes Showcase. Showcase proved the value of development-time capture; Spectra makes that workflow cross-platform and organized enough to become the long-term demo library. The site should now treat Spectra as the default capture recommendation and Showcase as the legacy migration path.
Worked Example
Consider a demo that needs to show the same product flow on its web app and its macOS companion. Previously this required Chrome DevTools scripting for the browser session and a separate manual walkthrough for the native app, with no shared place for the resulting assets.
With Spectra, a single capture session spans both surfaces. For the web leg, the Node runtime attaches over Chrome DevTools Protocol and steps through the flow, taking screenshots at each point in the guided usage sequence. For the macOS leg, the Swift native bridge drives the same kind of walkthrough through the Accessibility API, so the app does not need scripted UI hooks to be captured. iOS/watchOS legs of the same flow route through simulator control instead.
Each screenshot in the session carries framing metadata and tags, and the full set — web and macOS together — lands in one local library entry with an export manifest, rather than in two disconnected asset folders. This is the mechanism that lets Spectra replace Showcase as the default: Showcase’s development-time capture covered one platform at a time; Spectra’s session model is what makes the cross-platform library possible.
Capture duration, session count, and library size: ⚠️ no benchmark yet — the write-up does not report usage figures for this workflow.