{"id":50103915,"url":"https://github.com/agent-pattern-labs/geometra","last_synced_at":"2026-06-01T23:00:56.979Z","repository":{"id":347972503,"uuid":"1195941645","full_name":"Agent-Pattern-Labs/geometra","owner":"Agent-Pattern-Labs","description":"The Browser for the Singularity! No browser. Just computed geometry going straight to pixels. MCP replacement for Playwright too!","archived":false,"fork":false,"pushed_at":"2026-06-01T05:17:02.000Z","size":4374,"stargazers_count":26,"open_issues_count":2,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-01T07:14:43.127Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://geometra.razroo.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Agent-Pattern-Labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-30T08:04:57.000Z","updated_at":"2026-06-01T05:16:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"2540f127-6eee-458d-858e-9dda44d2ce48","html_url":"https://github.com/Agent-Pattern-Labs/geometra","commit_stats":null,"previous_names":["razroo/textrura-framework","agent-pattern-labs/geometra"],"tags_count":131,"template":false,"template_full_name":null,"purl":"pkg:github/Agent-Pattern-Labs/geometra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Agent-Pattern-Labs%2Fgeometra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Agent-Pattern-Labs%2Fgeometra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Agent-Pattern-Labs%2Fgeometra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Agent-Pattern-Labs%2Fgeometra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Agent-Pattern-Labs","download_url":"https://codeload.github.com/Agent-Pattern-Labs/geometra/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Agent-Pattern-Labs%2Fgeometra/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33797128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-23T09:04:39.305Z","updated_at":"2026-06-01T23:00:56.972Z","avatar_url":"https://github.com/Agent-Pattern-Labs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Geometra\n\n**The geometry protocol for UI.** Server-computed `{ x, y, w, h }` — not component descriptions — streamed to humans and AI agents over the same socket.\n\n\u003e **AI Agents:** See [`llms.txt`](llms.txt) for a structured overview of the entire framework — architecture, props, components, protocols, and APIs.\n\u003e **Agent-native apps:** See [`AGENT_NATIVE_UI.md`](AGENT_NATIVE_UI.md) for exact semantic geometry, stable UI ids, runtime commands, gateway inspect/actions, trace, and replay.\n\n**[Live Demo](https://geometra.razroo.com)** | **[npm](https://www.npmjs.com/org/geometra)** | **[GitHub](https://github.com/razroo/geometra)** | **[Auth](https://github.com/razroo/geometra-auth)** | **[Token Registry](https://github.com/razroo/geometra-token-registry)**\n\nhttps://github.com/user-attachments/assets/1610d856-3c7d-4fce-be42-1c43306e6520\n\n## MCP Server — AI UI Automation\n\nGeometra ships with [`@geometra/mcp`](mcp/README.md), an MCP server for AI agents that can:\n\n- connect directly to native Geometra apps over the geometry protocol\n- open and drive normal websites through `@geometra/proxy`\n- fill long forms semantically with `geometra_fill_fields`\n- query, wait on, and verify UI state without screenshots or vision models\n- start lower-turn flows by inlining `pageModel` or `formSchema` directly in `geometra_connect`\n\nUse Geometra MCP as the default interface when an LLM needs to explore, read, and act on a UI with lower token pressure than snapshot-heavy browser tooling. Keep Playwright-style tooling for deterministic scripted tests, exact low-level control, and site-specific fallback cases.\n\n### Geometra MCP vs Playwright MCP\n\nPlaywright MCP gives an agent raw browser automation primitives — click coordinates, fill selectors, evaluate JavaScript. The agent must orchestrate every low-level step. Geometra MCP wraps the same Chromium engine (via `@geometra/proxy`) but adds a **semantic layer purpose-built for LLM agents**, making it faster, cheaper, and more resilient for real-world workflows like filling job applications.\n\n| Concern | Playwright MCP | Geometra MCP |\n|---|---|---|\n| **Form discovery** | Agent must query DOM or a11y tree, then map fields manually | `geometra_form_schema` returns all fields with stable IDs and labels in one call |\n| **Form filling** | One click + type per field — 20 fields = 20+ tool calls | `geometra_fill_form` fills an entire form by label or ID in a single call |\n| **Custom dropdowns** | Agent writes bespoke click sequences per site (Workday, Greenhouse, Lever all differ) | `geometra_pick_listbox_option` handles custom comboboxes with keyboard fallback |\n| **File uploads** | Agent must locate the input, trigger the chooser, handle dialogs | `geometra_upload_files` auto-detects strategy: label match, hidden input, native chooser, or synthetic drop |\n| **Page understanding** | Agent receives raw DOM or screenshots — expensive to parse | `geometra_page_model` returns a structured summary (forms, landmarks, dialogs, actions) |\n| **Token cost** | Full DOM snapshots or base64 screenshots burn thousands of tokens | Compact geometry JSON — viewport-visible nodes only, minified by default |\n| **Waiting** | `page.waitForSelector` with CSS selectors the agent must guess | `geometra_wait_for` uses semantic conditions (role, state, text content) |\n| **Batch actions** | Each action is a separate tool roundtrip | `geometra_run_actions` executes multi-step workflows in one call |\n| **Value aliasing** | Exact string match only — \"US\" won't match \"United States\" | Built-in aliases: \"US\" ↔ \"USA\", \"Yes\" ↔ \"Agree\" ↔ \"Accept\", city abbreviations (NYC → New York) |\n| **Resume parsing** | Agent must poll or guess when parsing completes | `geometra_wait_for_resume_parse` handles the \"Parsing...\" spinner pattern directly |\n\n**When to use Geometra MCP:** Any time an LLM agent needs to interact with a UI — filling forms, navigating workflows, reading page state. The semantic tools reduce round-trips, cut token costs, and handle the messy inconsistencies of real-world sites.\n\n**When to stick with Playwright MCP:** Deterministic scripted test suites, pixel-level assertions, or cases requiring direct JavaScript evaluation in the page context.\n\n### Install\n\n\u003cdetails\u003e\n\u003csummary\u003eClaude Code\u003c/summary\u003e\n\n**One-line install:**\n```bash\nclaude mcp add geometra -- npx -y @geometra/mcp\n```\n\n**Uninstall:**\n```bash\nclaude mcp remove geometra\n```\n\nOr manually add to `.mcp.json` (project-level) or `~/.claude/settings.json` (global):\n```json\n{\n  \"mcpServers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall manually, remove the `geometra` entry from the config file.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eClaude Desktop\u003c/summary\u003e\n\nAdd to your Claude Desktop MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall, remove the `geometra` entry from the config file.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOpenAI Codex\u003c/summary\u003e\n\nAdd to your Codex MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall, remove the `geometra` entry from the config file.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCursor\u003c/summary\u003e\n\nOpen Settings → MCP → Add new MCP server, or add to `.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall, remove the entry from MCP settings.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWindsurf\u003c/summary\u003e\n\nAdd to `~/.codeium/windsurf/mcp_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall, remove the entry from the config file.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eVS Code / Copilot\u003c/summary\u003e\n\n**One-line install:**\n```bash\ncode --add-mcp '{\"name\":\"geometra\",\"command\":\"npx\",\"args\":[\"-y\",\"@geometra/mcp\"]}'\n```\n\nOr add to `.vscode/mcp.json`:\n```json\n{\n  \"servers\": {\n    \"geometra\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@geometra/mcp\"]\n    }\n  }\n}\n```\n\nTo uninstall, remove the entry from MCP settings or delete the server from the MCP panel.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOther MCP clients\u003c/summary\u003e\n\nAny MCP client that supports stdio transport can use Geometra. The server config is:\n\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@geometra/mcp\"]\n}\n```\n\nTo uninstall, remove the server entry from your client's MCP configuration.\n\n\u003c/details\u003e\n\nSee [mcp/README.md](mcp/README.md) for tool details, examples, and source installs from this repo.\n\n## Agent-Native UI Protocol\n\nGeometra can make the UI itself the agent contract: exact semantic geometry, stable UI ids, action policy, before/after replay, and postcondition checks from the same tree that renders to humans.\n\n| Browser automation | Geometra-native UI |\n|---|---|\n| Infer state from DOM, screenshots, selectors, or OCR | Inspect `semantic.id`, role/name/state, exact bounds, and action contracts directly |\n| Click guessed selectors or coordinates | Click/focus/type by stable UI id |\n| Audit backend calls separately from what was visible | Replay frame-before/frame-after geometry plus action trace |\n| Add policy and approval as extra app logic | Carry risk, confirmation, input/output schemas, and postconditions with the UI action |\n\nRun the end-to-end external-agent flow:\n\n```bash\nbun run demo:agent-native:http\n```\n\nIt starts a local gateway, calls `/inspect`, requests and approves `approve-payout`, reads `/replay`, and writes `examples/replays/claims-review.json`.\n\nThe hosted demo build includes the agent-native claims page at `/agent-native-ops/` and a visual audit packet viewer at `/replay-viewer/`.\n\nFor the vertical wedge, see [`CLAIMS_COMPLIANCE_WORKSTATIONS.md`](CLAIMS_COMPLIANCE_WORKSTATIONS.md). To scaffold the same pattern, run:\n\n```bash\nbun run create:app -- ./claims-workstation --template agent-workstation\n```\n\n## Agent-native roadmap\n\nThe next layer is explicit agent contracts on top of geometry: stable action ids, risk classes, policy gates, traces, and replay. Start with:\n\n- [Agent-native protocol](AGENT_NATIVE_PROTOCOL.md)\n- [Agent contracts](AGENT_CONTRACTS.md)\n- [Agent benchmark suite](AGENT_BENCHMARK_SUITE.md)\n- [Agent gateway](AGENT_GATEWAY.md)\n- [Security model](AGENT_SECURITY_MODEL.md)\n- [Devtools and replay](AGENT_DEVTOOLS_REPLAY.md)\n- [Business value](BUSINESS_VALUE.md)\n\nTry the enterprise workflow demo with `bun run --filter @geometra/demo-agent-native-ops dev`, or run the deterministic value harness with `bun run benchmark:agent-native:assert`.\n\nThe first runtime slice is available through `createAgentGateway()` in `@geometra/core` and the HTTP/tool transport in `@geometra/gateway`: frame-bound action catalogs, tenant-scoped API keys, approvals, redaction, replay persistence, and MCP-style gateway tools.\n\n## Why geometry, not components?\n\nOther agent-to-UI systems (json-render, A2UI, computer-use agents) send **component descriptions** or scrape rendered output. The agent still has to interpret what it sees. Geometra sends **pixel-exact geometry** — every element's position and size, computed on the server, streamed as flat JSON. Nothing to interpret. Nothing to scrape.\n\nThis matters for three audiences:\n\n### AI agents\nAgents connect to the same WebSocket as human clients. They get `{ x, y, w, h }` geometry + semantic metadata — no browser, no headless Chrome, no vision model. Interaction uses the same `event`/`key` messages the renderer sends. JSON speed, not browser speed.\n\n### Ultra-constrained clients\nA Raspberry Pi, kiosk, or ESP32 with a display can be a Geometra client. The thin client (~2KB) receives pre-computed coordinates and paints them. Zero layout work on the client.\n\n### Deterministic testing\nLayout output is JSON. Assert on `{ x, y, w, h }` directly — no screenshot diffs, no Playwright, no headless browser in CI. Milliseconds, not seconds.\n\n### Architecture at a glance\n\n- **Server-computed** — clients never pay layout cost, just paint pre-computed coordinates\n- **WASM layout** — Yoga flexbox runs at near-native speed\n- **Geometry diffs** — updates send only changed `{ x, y, w, h }`, not full re-renders\n- **No DOM** — zero style recalculation, zero reflow, zero composite\n- **No framework runtime on client** — the thin client is a paint loop, not a reconciler\n- **Multi-instance** — run multiple server/client pairs in a single process for parallel AI workloads\n\n### \"Server is client\" — what does that actually mean?\n\nIf you come from a backend/API background, this phrasing can be confusing. **Geometra does not replace your REST or GraphQL API.** Your business logic, data layer, and API endpoints stay exactly where they are.\n\nHere, \"server\" and \"client\" refer to the **rendering pipeline**, not the API layer:\n\n```\nTraditional web app:\n  API Server (business logic) → Browser (layout + paint)\n\nGeometra:\n  API Server (business logic) → Geometra Server (layout computation) → Thin Client (paint only)\n                                       ↑\n                               AI agents connect here too\n```\n\nThe **Geometra server** is a layout computation process. It takes your UI tree, runs Yoga WASM flexbox, and outputs pure geometry (`{ x, y, width, height }`). The **thin client** receives that geometry over WebSocket and paints it — no layout engine, no DOM, just pixels.\n\nThe key insight: because layout output is just JSON coordinates, an AI agent can consume it directly — same protocol, no browser needed. And because either side can run the layout engine, you can compute layout on the client (local mode) or server (streamed mode) using the same code.\n\nYour app still calls your API for data. Geometra handles what happens *after* you have the data: turning it into pixels.\n\n### Agents and renderers are the same class of client\n\nIn a traditional web stack, an AI agent and a human user interact with fundamentally different interfaces. The human gets pixels; the agent scrapes DOM, parses accessibility trees, or interprets screenshots. They are different classes of client.\n\nIn Geometra, both consume the same WebSocket stream of `{ x, y, width, height }` geometry plus semantic metadata. The `@geometra/client` (~2KB paint loop) is just one consumer of that stream. An AI agent is another — same protocol, same data, no translation layer. This isn't a bolted-on \"AI mode\"; it's a consequence of the architecture. When layout output is structured data over a socket, every consumer is a thin client.\n\n```\nTraditional:\n  Server → HTML/CSS/JS → Browser renders pixels → Human sees UI\n  Server → HTML/CSS/JS → Headless browser → Scraper → Agent sees DOM\n\nGeometra:\n  Server → JSON geometry stream → Canvas renderer → Human sees UI\n  Server → JSON geometry stream → Agent reads JSON directly\n                                  ↑ same socket, same data\n```\n\nThis means agents can observe UI state, interact with elements (via the same `event`/`key`/`composition` messages the client sends), and verify outcomes — all at JSON speed, not browser speed.\n\n### Why this replaces browser automation (Playwright, Puppeteer, etc.)\n\nBrowser automation tools solve a specific problem: programmatically controlling a system (the browser) that was designed for humans. They launch a real browser, wait for layout/paint, query the DOM, simulate clicks, and assert on rendered state. This is expensive, flaky, and slow — because the browser was never designed to be an API.\n\nGeometra eliminates the need for this entire category of tooling:\n\n| Concern | Playwright approach | Geometra approach |\n|---|---|---|\n| **Observe UI state** | Query DOM or accessibility tree from headless browser | Read geometry JSON directly from WebSocket |\n| **Interact with elements** | Simulate mouse/keyboard events through browser APIs | Send `event`/`key` messages on the same WebSocket |\n| **Assert on layout** | Screenshot comparison or DOM assertions | JSON snapshot: `expect(layout).toMatchSnapshot()` |\n| **Test in CI** | Headless Chromium (~200MB) + browser launch overhead | Yoga WASM (~200KB) + geometry assertions in-process |\n| **Speed** | Seconds per test (browser startup + rendering + waiting) | Milliseconds (JSON in, JSON out, no browser) |\n\nThis doesn't mean Playwright is useless in general — it's still the right tool for testing DOM-based apps. But for Geometra apps, the entire concept of \"browser automation\" is a solved problem at the protocol level. The geometry stream *is* the test interface.\n\nSee `GEOMETRY_SNAPSHOT_TESTING.md` for CI patterns using layout JSON assertions.\n\n### How this compares to agent-to-UI approaches\n\nMost agent-to-UI systems — json-render (Vercel), A2UI (Google), computer-use agents, accessibility-tree scrapers — share the same fundamental constraint: they send **component descriptions** or scrape rendered output, so the agent still needs a translation layer. Geometra sends **pixel-exact geometry**. The distinction matters:\n\nThese approaches typically:\n1. **Scrape** — parse DOM, accessibility trees, or screenshots after the browser renders\n2. **Interpret** — use vision models or heuristics to map pixels/DOM to semantic meaning\n3. **Act** — inject synthetic events through browser automation APIs\n4. **Verify** — re-scrape to confirm the action worked\n\nEach step is lossy, slow, and fragile. The agent is reverse-engineering a human interface.\n\nGeometra inverts this. The server already produces structured, semantic data as its *primary output* — not as a retrofit. An agent connecting to a Geometra server gets:\n\n- **Exact geometry** — every element's position and size, no OCR or bounding-box estimation\n- **Semantic metadata** — roles, labels, focusable state, from `toAccessibilityTree()` built into the pipeline\n- **Interaction parity** — the same `event`/`key`/`resize` messages the human client sends\n- **Real-time updates** — geometry diffs stream over WebSocket, no polling or re-scraping\n\nThe agent doesn't need to scrape, interpret, or guess. It reads the same structured protocol the renderer reads. This is not \"AI-accessible UI\" — it's UI that was never inaccessible to machines in the first place.\n\n### Edge and resource-constrained hardware\n\nThe traditional web stack assumes a full browser engine on the client: HTML parser, CSS engine, JavaScript runtime, layout engine, compositor. That's hundreds of megabytes before your app loads. This makes serving real web UI on embedded devices, kiosks, IoT dashboards, or edge nodes impractical.\n\nGeometra's pipeline breaks this assumption:\n\n| Component | Size | Runs where |\n|---|---|---|\n| Yoga WASM (layout engine) | ~200KB | Server or client |\n| Thin client (paint loop) | ~2KB | Client |\n| Canvas/Terminal renderer | Small, pluggable | Client |\n| Layout computation | Zero on client in server-computed mode | Server |\n\nIn server-computed mode, the client does *zero layout work*. It receives pre-computed coordinates and paints them. A Raspberry Pi, an ESP32 with a display, or a terminal on a remote server can be a Geometra client.\n\nThe JSON-native protocol also opens an interesting door for fine-tuned models. The entire UI lifecycle is JSON manipulation:\n\n- **Tree construction**: generate `box()`/`text()` trees (structured JSON)\n- **Layout output**: `{ x, y, width, height }` (flat JSON)\n- **Updates**: geometry diffs (JSON patches)\n- **Interaction**: `event`/`key` messages (JSON)\n\nA small model fine-tuned on JSON manipulation could drive the entire UI pipeline — generating views, processing updates, handling interaction — without ever touching HTML, CSS, or a browser API. On edge hardware where you can't run a browser but *can* run a quantized model + Yoga WASM, this becomes a viable path to serving real interactive UI.\n\n```\nEdge deployment:\n  Fine-tuned model (JSON generation) → Geometra server (Yoga WASM layout)\n       ↓\n  WebSocket geometry stream → Thin client on display hardware\n```\n\nThis is particularly relevant for:\n- **Industrial dashboards** on ARM/RISC-V devices with limited memory\n- **Kiosk/signage** where a browser engine is overkill for the interaction model\n- **Multi-instance AI workloads** where many UI sessions run server-side and stream to lightweight displays\n- **Offline-capable edge nodes** where the model + Yoga WASM run locally without internet\n\n### Benchmark Comparison\n\n| Metric | Geometra | React (DOM) | SSR (Next.js etc.) |\n|---|---|---|---|\n| Layout engine | Yoga WASM (near-native) | Browser layout (style recalc + reflow) | Server HTML → browser reparse + layout |\n| Client runtime | ~2KB paint loop | ~40-100KB+ framework runtime | ~40-100KB+ hydration runtime |\n| AI agent access | Direct JSON protocol, no browser | Requires headless browser or scraping | Requires headless browser or scraping |\n| Update payload | Geometry diff: `{ x, y, w, h }` | Virtual DOM diff → DOM mutations | Full page or partial HTML |\n| Layout computation | Server or client (same code) | Client only | Server (HTML) → client (re-layout) |\n| DOM dependency | None | Full DOM API | Full DOM API (hydration) |\n| Multi-instance | Multiple server/client pairs in one process | One app per page | One app per request |\n| Time to interactive | Instant (geometry is pre-computed) | After hydration + layout | After HTML parse + hydration + layout |\n\n- Dashboard: https://geometra.razroo.com/\n- Agent-native claims demo: https://geometra.razroo.com/agent-native-ops/\n\n## How It Works\n\n```\nTraditional:  HTML → CSS Parser → DOM → Layout → Paint → Composite\nGeometra:     Declarative Tree → Yoga WASM → Computed Geometry → Render Target\n```\n\nThe framework replaces the entire browser rendering pipeline. Layout is computed via Yoga (Facebook's flexbox engine compiled to WASM). Text is measured via Pretext. The output is pure geometry — `{ x, y, width, height }` — rendered by pluggable backends: Canvas2D, Terminal, or raw geometry for AI agents.\n\n## Packages\n\n| Package | Description |\n|---|---|\n| `@geometra/core` | Component model, signals, hit-testing, semantic/a11y tree generation, text-input primitives |\n| `@geometra/renderer-canvas` | Canvas2D paint backend + selection + optional accessibility mirror |\n| `@geometra/renderer-terminal` | ANSI terminal/TUI paint backend |\n| `@geometra/renderer-webgpu` | WebGPU renderer scaffold (capability detection + initialization surface) |\n| `@geometra/server` | Server-side layout engine with WebSocket geometry streaming (versioned protocol) |\n| `@geometra/client` | Thin client that receives pre-computed geometry and paints it (versioned protocol checks) |\n| `@geometra/ui` | 31-component UI library: button, input, textarea, checkbox, radio, switch, slider, select, combobox, dialog, sheet, accordion, tabs, card, badge, alert, toast, progress, skeleton, avatar, separator, breadcrumb, pagination, menu, command palette, data table, tree view, list |\n| `@geometra/router` | Renderer-agnostic data router: nested routes, loaders/actions, redirects, blockers, lazy/prefetch, protocol-aware navigation |\n| `@geometra/tw` | Tailwind-style utility classes — converts class strings like `\"flex-row p-4 bg-blue-500\"` into Geometra props |\n\nPackage docs:\n\n- `textura`: `packages/textura` — DOM-free Yoga WASM layout engine\n- `@geometra/core`: `packages/core/README.md`\n- `@geometra/renderer-canvas`: `packages/renderer-canvas/README.md`\n- `@geometra/renderer-terminal`: `packages/renderer-terminal/README.md`\n- `@geometra/renderer-webgpu`: `packages/renderer-webgpu/README.md`\n- `@geometra/renderer-three`: `packages/renderer-three` — Three.js hosts + scene3d\n- `@geometra/server`: `packages/server/README.md`\n- `@geometra/client`: `packages/client/README.md`\n- `@geometra/ui`: `packages/ui/README.md`\n- `@geometra/router`: `packages/router/README.md`\n- `@geometra/tw`: `packages/tw` — Tailwind-style utility classes\n\n## Start Here\n\nIf you want a real Geometra app instead of isolated package snippets, start with the official full-stack scaffold. It matches the recommended architecture from the live demo: `@geometra/ui + @geometra/router + @geometra/server/@geometra/client`.\n\n```bash\ngit clone https://github.com/razroo/geometra.git\ncd geometra\nnpm install\nnpm run create:app -- ./my-geometra-app\ncd my-geometra-app\nnpm install\nnpm run server\nnpm run client\n```\n\nUse `npm run create:app -- --list` to see the other templates (`canvas-local`, `server-client`, and `terminal`). The matching reference implementation lives in `demos/full-stack-dashboard`.\n\n## Quick Start\n\n### Phase 1: Local Canvas Rendering\n\n```ts\nimport { signal, box, text, createApp } from '@geometra/core'\nimport { CanvasRenderer } from '@geometra/renderer-canvas'\n\nconst count = signal(0)\n\nconst renderer = new CanvasRenderer({\n  canvas: document.getElementById('app') as HTMLCanvasElement,\n  background: '#1a1a2e',\n})\n\nfunction view() {\n  return box({ flexDirection: 'column', padding: 24, gap: 16 }, [\n    text({\n      text: `Count: ${count.value}`,\n      font: 'bold 24px Inter',\n      lineHeight: 32,\n      color: '#ffffff',\n    }),\n    box({\n      backgroundColor: '#e94560',\n      padding: 12,\n      borderRadius: 8,\n      onClick: () =\u003e count.set(count.peek() + 1),\n    }, [\n      text({\n        text: 'Increment',\n        font: '16px Inter',\n        lineHeight: 22,\n        color: '#ffffff',\n      }),\n    ]),\n  ])\n}\n\nawait createApp(view, renderer, { width: 400, height: 300 })\n```\n\n#### With `@geometra/tw` (Tailwind-style shorthand)\n\n```ts\nimport { tw } from '@geometra/tw'\n\n// Before:\nbox({ flexDirection: 'column', padding: 24, gap: 16, backgroundColor: '#1e293b', borderRadius: 8 }, children)\n\n// After:\nbox(tw(\"flex-col p-6 gap-4 bg-slate-800 rounded-lg\"), children)\n```\n\n### Phase 2: Server-Computed Layout\n\n**Server** (Node.js/Bun — no browser needed):\n\n```ts\nimport { signal, box, text } from '@geometra/core/node'\nimport { createServer } from '@geometra/server'\n\nconst data = signal(['Hello', 'from the server'])\n\nfunction view() {\n  return box({ flexDirection: 'column', padding: 20, gap: 8 },\n    data.value.map(msg =\u003e\n      box({ backgroundColor: '#16213e', padding: 12, borderRadius: 8 }, [\n        text({ text: msg, font: '14px Inter', lineHeight: 20, color: '#fff' }),\n      ])\n    )\n  )\n}\n\nconst server = await createServer(view, { port: 3100, width: 600, height: 400 })\n```\n\n**Client** (thin — just a paint loop):\n\n```ts\nimport { CanvasRenderer } from '@geometra/renderer-canvas'\nimport { createClient } from '@geometra/client'\n\nconst canvas = document.getElementById('app') as HTMLCanvasElement\n\ncreateClient({\n  url: 'ws://localhost:3100',\n  renderer: new CanvasRenderer({ canvas }),\n  canvas,\n})\n```\n\nThe client never runs a layout engine. It receives pre-computed `{ x, y, width, height }` geometry over WebSocket and paints it.\n\n### Phase 3: Terminal Rendering\n\n```ts\nimport { signal, box, text, createApp } from '@geometra/core/node'\nimport { TerminalRenderer } from '@geometra/renderer-terminal'\n\nconst renderer = new TerminalRenderer()\n\nfunction view() {\n  return box({ flexDirection: 'column', padding: 16, gap: 8 }, [\n    box({ backgroundColor: '#0a0a2e', padding: 12 }, [\n      text({ text: 'GEOMETRA TUI', font: 'bold 20px monospace', lineHeight: 26, color: '#e94560' }),\n    ]),\n    text({ text: 'Flexbox layout in your terminal.', font: '14px monospace', lineHeight: 18, color: '#aaa' }),\n  ])\n}\n\nawait createApp(view, renderer, { width: 533, height: 320 })\n```\n\n## Reactivity\n\nGeometra uses a minimal signals system. When a signal changes, only the affected parts of the tree re-layout and re-render.\n\n```ts\nimport { signal, computed, effect, batch } from '@geometra/core'\n\nconst name = signal('world')\nconst greeting = computed(() =\u003e `Hello, ${name.value}!`)\n\neffect(() =\u003e console.log(greeting.value))  // \"Hello, world!\"\n\nname.set('Geometra')                        // \"Hello, Geometra!\"\n\n// Batch multiple updates into one flush\nbatch(() =\u003e {\n  a.set(1)\n  b.set(2)\n})\n```\n\n## Event Handling\n\nEvents are resolved via hit-testing against the computed geometry tree — no DOM event system involved.\n\n```ts\nbox({\n  backgroundColor: '#e94560',\n  padding: 16,\n  onClick: (e) =\u003e console.log(`Clicked at ${e.x}, ${e.y}`),\n  onPointerDown: (e) =\u003e { /* ... */ },\n  onPointerUp: (e) =\u003e { /* ... */ },\n  onPointerMove: (e) =\u003e { /* ... */ },\n}, [\n  text({ text: 'Click me', font: '16px Inter', lineHeight: 22, color: '#fff' }),\n])\n```\n\n## Routing Quick Start\n\nGeometra routing is available in `@geometra/router` and is renderer-agnostic.\n\n```ts\nimport { createRouter, createMemoryHistory, link, matchRouteTree } from '@geometra/router'\n\nconst router = createRouter({\n  history: createMemoryHistory({ initialEntries: ['/'] }),\n  routes: [\n    { id: 'home', path: '/' },\n    { id: 'users', path: '/users/:id' },\n    { id: 'not-found', path: '/*' },\n  ],\n})\n\nrouter.start()\nawait router.navigate('/users/42')\n```\n\nFor full routing details, see `packages/router/README.md` and `ROUTER_DELIVERY_REPORT.md`.\n\n## Accessibility and Text Input Foundations\n\nGeometra now exposes runtime primitives so non-DOM renderers can still provide accessibility and editing behavior:\n\n- `toAccessibilityTree(tree, layout)` in `@geometra/core` maps UI + geometry to role/name/bounds/focusable nodes.\n- `createBrowserCanvasClient(...)` in `@geometra/renderer-canvas` is the official browser host bootstrap for thin-client canvas apps.\n- `enableAccessibilityMirror(host, renderer)` in `@geometra/renderer-canvas` syncs a hidden DOM mirror for assistive tech.\n- `insertInputText`, `replaceInputSelection`, `backspaceInput`, `deleteInput`, `moveInputCaret` in `@geometra/core` provide selection-aware text editing logic you can wire to keyboard handlers.\n\n### Text-input semantics\n\n- Input state uses `{ nodes, selection }`, where `selection` is `anchor*`/`focus*` node-local offsets.\n- Editing helpers normalize reversed selections, replace selected ranges first, then collapse caret at insertion/deletion end.\n- `moveInputCaret(state, dir, true)` extends selection from the anchor; without extend it collapses to directional edge first, then moves.\n- `Backspace` at node start merges with previous node; `Delete` at node end merges with next node.\n- Composition flow should snapshot selection on `onCompositionStart`, update transient draft on `onCompositionUpdate`, and commit text on `onCompositionEnd`.\n- `getInputCaretGeometry` only returns non-null for collapsed selections and clamps offsets to measured text bounds.\n\n### Accessibility guarantees and current limitations\n\nGuarantees:\n\n- `toAccessibilityTree(tree, layout)` provides deterministic role/name/bounds/focusable output from the rendered geometry tree.\n- Semantic hints (`tag`, `role`, `ariaLabel`, `alt`) are preserved in a11y/SEO projections.\n- Common container patterns (main/nav/article/list/form/button/input-like) map to stable roles.\n\nCurrent limitations:\n\n- Accessibility output is structural and does not implement full platform accessibility APIs by itself.\n- Full platform accessibility API parity is not implemented by core alone; canvas apps should integrate `enableAccessibilityMirror` and validate host/browser assistive-tech behavior.\n- Text measurement parity across environments still depends on available canvas measurement backends and font availability.\n- Terminal keyboard escape-sequence normalization can vary by emulator; keep terminal integration tests in CI for your target environments.\n\nForm semantics examples are available in `FORM_SEMANTICS_EXAMPLES.md`.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────┐\n│                  Application                      │\n│  Components → Signals → Layout Trees              │\n├──────────────────────────────────────────────────┤\n│              @geometra/core                        │\n│  box() / text() → toLayoutTree() → computeLayout()│\n├──────────────────────────────────────────────────┤\n│              textura (layout engine)               │\n│  Yoga WASM + Pretext → { x, y, width, height }   │\n├───────────┬───────────┬───────────┬──────────────┤\n│ Canvas2D  │  Terminal  │  Server   │ Raw Geometry  │\n│ Renderer  │  Renderer  │ → Client  │ (AI Agents)   │\n└───────────┴───────────┴───────────┴──────────────┘\n```\n\n## Protocol (v1)\n\nClient and server exchange JSON messages over WebSocket with optional `protocolVersion`.\n\n- **Server -\u003e Client**\n  - `frame`: `{ type: 'frame', layout, tree, protocolVersion?: 1 }`\n  - `patch`: `{ type: 'patch', patches, protocolVersion?: 1 }`\n  - `error`: `{ type: 'error', message, protocolVersion?: 1 }`\n- **Client -\u003e Server**\n  - `event`: pointer/click hit-test events (`onClick`, `onPointerDown`, `onPointerUp`, `onPointerMove`)\n  - `key`: keyboard events (`onKeyDown`, `onKeyUp`)\n  - `composition`: IME events (`onCompositionStart`, `onCompositionUpdate`, `onCompositionEnd`)\n  - `resize`: viewport updates (`width`, `height`)\n\nCompatibility notes:\n\n- Unversioned messages are treated as protocol v1.\n- If one side receives a **newer** protocol version than it supports, it returns/raises an error instead of silently misbehaving.\n- Server layout dimensions can be updated live via `resize`, allowing true server-computed responsive layouts.\n\nSee `PROTOCOL_COMPATIBILITY.md` for the explicit compatibility policy and change process.\n\n## Running the Demos\n\n```bash\nnpm install\n\n# Phase 1: Local canvas rendering\ncd demos/local-canvas \u0026\u0026 npm run dev\n\n# Phase 2: Server-client (run in two terminals)\ncd demos/server-client \u0026\u0026 npm run server   # terminal 1\ncd demos/server-client \u0026\u0026 npm run client   # terminal 2\n\n# Phase 3: Terminal UI\ncd demos/terminal \u0026\u0026 npm run dev\n\n# Text input playground (canvas)\ncd demos/text-input-canvas \u0026\u0026 npm run dev\n\n# Auth + @geometra/token-registry + remoteVerifier (registry + Geometra + Vite in one shell)\nnpm run demo:auth-registry\n```\n\nSee `demos/auth-registry-server-client/README.md` for details. Terminal input/focus wiring snippets are in `TERMINAL_INPUT_EXAMPLES.md`.\n\n## Known caveats\n\n- Server-side text measurement in pure Node environments requires an available canvas measurement backend (for example OffscreenCanvas/polyfill paths).\n- Terminal key escape sequences can vary by terminal emulator; integration tests include normalized paths for Tab/Shift+Tab/arrows.\n- Canvas accessibility parity depends on host/browser support for hidden accessibility mirror strategies.\n- Protocol mismatches are rejected explicitly when peer version is newer; keep release notes and protocol docs in sync when changing wire shapes.\n\nBun equivalents (faster install/startup in many environments):\n\n```bash\nbun install\nbun run demo:build\nbun run test      # default fast suite\nbun run test:all  # full suite including slow exhaustive cases\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagent-pattern-labs%2Fgeometra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagent-pattern-labs%2Fgeometra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagent-pattern-labs%2Fgeometra/lists"}