BOXY

Reference

Components

Every component here is live and built from the role tokens. Change the theme or density in the header and they all update in place. Press Ctrl K for the command palette.

01 / Buttons

One primary action per view

Other buttons are outline or ghost. Buttons in a group share their borders, so two 1px lines never end up next to each other.

Variants
Sizes
Group
Segmented
Range
Checked segment inverts · see 15

02 / Fields

Labels go above, and helper text stays visible

There are no floating labels. Their animation and their spot on the border both clash with the rest of the system. Focus draws an inset ring, so the layout doesn't move.

Boxed (default)

Lowercase, hyphens only.

This key has been revoked.

Underlined (industrial)

Textarea & search

⌘K

03 / Selection

The radio is a square too

This breaks with convention on purpose, and people push back on it more than anything else. Keep it anyway. One round control in a square interface looks like a mistake.

Checkbox
Radio
Toggle

04 / Tags & status

Tags and status marks are square

No pills and no round dots. A status always has both a shape and a word.

Tags
neutral accent passing degraded failing 128 small
Status
Operational Degraded Outage Not deployed
Keys
⌘K esc ⇧↵

05 / Cards

Cards share one grid and one set of lines

The grid has a 1px gap over a background in the border colour, and that gap is the border you see. The cards have no borders of their own, so lines never double up or drift out of line.

01

Immutable deploys

Every build is content-addressed and kept for 90 days. Roll back in under a second.

Learn more →

02

Edge routing

Requests terminate at the nearest of 310 locations, with automatic failover.

Learn more →

03

Zero-config TLS

Certificates issued, renewed and stapled without a line of configuration.

Learn more →

Deployment

edge-router

live

Pushed 12 minutes ago by a teammate from main at 8f3a1c.

Stat tiles

Requests

2.41M

▲ 12.4% vs last week

Error rate

0.04%

▲ 0.01pp vs last week

06 / Tabs & table

Boxy is at its best with dense data

Headers are uppercase mono on a darker strip. Rows are split by 1px lines, with no vertical lines. Numbers are right-aligned with tabular figures. Use the arrow keys to move between tabs.

ServiceRegionStatus p95RequestsError rate
edge-routerus-east-1Healthy41 ms2,410,8820.04%
api-gatewayeu-west-2Healthy88 ms1,092,4410.11%
image-proxyap-south-1Degraded612 ms318,2042.80%
webhook-fanoutus-east-1Failing—0100.00%
cron-workereu-west-2Paused—0—
Showing 1–5 of 1,284

07 / Feedback

Callouts, overlays and progress

Scheduled maintenance

Read replicas will fail over on Sunday at 02:00 UTC.

Certificate issued

Auto-renews 30 days before expiry.

Approaching quota

You have used 84% of this month's build minutes.

Deployment failed

Build step 4 exited with code 1.

Overlays
Hover for a tooltip
Progress

68% · 34 of 50 steps

Indeterminate

Skeleton

09 / Popover & drawer

Popovers can hold controls. Tooltips can't.

A popover holds controls and stays open until you dismiss it. A drawer is a modal panel that opens from the end side and follows the same focus rules as a dialog.

Popover
Esc and outside-click dismiss · focus returns to the trigger
Drawer
400px · slides 100% in 160ms sharp · scrim, focus trap, Esc

11 / Accordion

Accordions built on native disclosure

It's built on <details>, so it works without JavaScript and the browser's find-in-page can open a matching item. Give the items the same name and only one can be open at a time.

Exclusive: one open at a time

01What counts as a build minute?

Wall-clock time from the first build step to the upload finishing, rounded up to the next minute per build.

02Can I bring my own domain?

Yes, on every plan. Point a CNAME at edge.orbit.app; certificates are issued automatically.

03What happens when I hit a limit?

Nothing stops. You get an email at 80% and 100%, and overage is billed at the published rate.

Independent: for settings groups

Build & output
Command
orbit build
Output
dist/
Advanced

12 / Code

Inline, block, numbered, diff and terminal

Each line is its own span.ln, so line numbers, highlights and diff marks belong to the line instead of sitting on top of it. The copy button copies the code without the line numbers.

Inline code sits in a sunken box with a subtle rule: run orbit deploy --prod, then check ORBIT_TOKEN is set. Keys use Ctrl K, and a match shows up as an inverted inline block instead of a highlighter.

send.tstypescript
export async function send(hook: Hook, body: string) {  for (let attempt = 0; attempt < 5; attempt++) {    const res = await fetch(hook.url, { method: "POST", body });    if (res.ok) return res;    // back off: 200ms, 400ms, 800ms ...    await sleep(200 * 2 ** attempt);  }  throw new WebhookError(hook.id);}
orbit.toml +2−1
[[routes]]pattern = "/api/*"timeout = 10timeout = 30retries = 5service = "api-gateway"
terminal
orbit deploy --prod✓ build       1.8s✓ upload      0.4s✓ propagate   2.1slive at https://orbit.app → 310 pops
exit 04.3s
install
npm install @orbit/sdk

13 / Lists

Square bullets, mono numerals, drawn checks

Bullets are squares too. Numbered lists use zero-padded mono numbers, so the alignment doesn't shift when a list reaches item 10.

Unordered

  • Immutable, content-addressed builds
  • Edge routing across 310 locations
    • Automatic failover
    • Per-route timeouts
  • Zero-config TLS

Ordered

  1. Install the CLI
  2. Run orbit init in your project
  3. Link a Git repository
  4. Push to deploy

Checklist & plan states

  • Reproduce the failing test
  • Add retry with backoff
  • Update the changelog
  • Unlimited preview deploys
  • SAML single sign-on

Ruled

  1. Create a project
  2. Connect a domain
  3. Invite the team

Description list

Service
edge-router
Region
us-east-1
Commit
8f3a1c2
Status
Healthy

Blockquote

We moved 40 services in a weekend and nobody noticed. That was the point.

Platform lead, Acme

14 / Date picker

The calendar is a grid of shared cells

Typing is still the main way to enter a date. The field accepts YYYY-MM-DD and the calendar is there to help. Arrow keys move by day and week, PgUp PgDn by month. Range pickers show presets first.

Field + popover

Type it, or pick from the calendar.

Inline

Range with presets

Click start, then end

Presets come first, because nobody wants to click around a grid to pick “last 30 days”.

15 / Slider, stepper & segmented

A square thumb, and always a number beside it

Sliders are for rough values. Put a number field next to one, so people can type 37 instead of trying to drag to it.

Slider
116324864
40%
Stepper
min 0 · max 12
Segmented
Time range
View
Built on native radios, so arrow keys and form values just work

16 / File upload

The one place a dashed line is allowed

A dashed line looks like a space waiting to be filled. Drag a file over it and the line turns solid accent. Errors show up on the file that caused them, not on the drop zone. Try dropping a file.

  • pdf

    q3-invoice-acme.pdf

    1.2 MB

    Done
  • csv

    requests-sep-2026.csv

    8.4 MB64%

    Uploading
  • mov

    launch-video-final-v3.mov

    184 MB · exceeds the 25 MB limit

    Failed

17 / Progress & meters

Quantities as cells, loading as a stepped square

A progress bar shows how far along a task is. A meter shows a level against a limit. The spinner is a 4px square stepping around the edge of a box, with no arcs anywhere.

Progress

Uploading assets68%
Build minutes84%

Approaching the monthly limit

Storage98%

Meter & steps

Seats14 / 20
Context window172k / 200k
OnboardingStep 3 of 5

Spinner & loading

16 / 12px
width fixed · no reflow

Indeterminate

18 / Avatars & activity

Square avatars, square presence, a literal timeline

Avatars are square like everything else. In a group they sit side by side and share borders, instead of overlapping like a stack of circles.

Sizes & presence

MK MK JR AO SL

Group

MKJRAOSL+3
7 collaborators

In a row

JR

Jo Rivera

jo@acme.dev · admin

Timeline

  1. 12:04:33

    Deploy succeeded

    edge-router · 8f3a1c2

  2. 11:58:10

    Jo Rivera promoted a preview

  3. 11:40:02

    p95 above 500ms in ap-south-1

    Auto-resolved after 6 minutes.

  4. 09:12:45

    Environment variable updated

19 / Layout primitives

Stack, cluster, grid, auto-grid, split

Five classes in boxy.css. Each one reads its gap from a single custom property, --bx-gap, so you pick a value from the space scale and never rebuild the layout yourself.

.bx-stack

Vertical flow, one gap

01
02
03
.bx-cluster

A wrapping row

edgetlsroutingcacheobservabilitystorage
.bx-grid

12 columns · 16 in industrial

span 8
span 4
3
3
span 6
.bx-auto-grid

Fits tracks of --bx-min; no breakpoints

cell
cell
cell
cell
cell
.bx-split

Side + main; wraps when main gets narrow

side · 200px
main · fluid

20 / Agent & chat

Agent chat reads like a transcript

There are no chat bubbles. Tool calls look like log lines, with status, name, arguments and duration, and expand to show their input and output. Reasoning is collapsed and muted. An approval is the only point where the agent waits for a person. You can type in the composer below.

You12:02

The webhook test is flaky in CI. Can you find out why and fix it?

Agent
Thought for 6s

Flaky suggests timing. The test posts to a mock that sometimes returns 503 on first boot. The sender has no retry, so any cold mock fails the run.

grep"send(" src/webhooks0.2s
Output
src/webhooks/send.ts:4   export async function send(hook, body)
src/webhooks/queue.ts:31  await send(hook, payload)
read_filesrc/webhooks/send.ts0.1s
Input
{ "path": "src/webhooks/send.ts", "lines": [1, 12] }
Output · 12 lines
export async function send(hook: Hook, body: string) {
  const res = await fetch(hook.url, { method: "POST", body });
  if (!res.ok) throw new WebhookError(hook.id);
  return res;
}
runnpm test -- webhooks4.8s
Output · exit 1
FAIL  webhooks/send.test.ts
  ✗ delivers to a cold endpoint (503 Service Unavailable)

Found it. send() gives up on the first non-2xx response, and the mock endpoint returns 503 for about 300ms after boot1. I'll add a bounded retry with exponential backoff.

Approval needed

Run a command that writes to the working tree:

npm test -- webhooks --update-snapshots
Asked 12:03:41
send.test.ts
↵ send · ⇧↵ newline

21 / Combobox & multi-select

Type to filter, arrows to move, Enter to take

Focus stays in the input the whole time, and the highlighted option is tracked with aria-activedescendant. The part of each option that matches what you typed is shown inverted. In the multi-select, chosen items become square tags inside the field, and Backspace in an empty input removes the last one.

Try “eu” or “south”.

  • us-east-1 · Virginia41 ms
  • us-west-2 · Oregon62 ms
  • sa-east-1 · São Paulo118 ms
  • eu-west-2 · London88 ms
  • eu-central-1 · Frankfurt91 ms
  • ap-south-1 · Mumbai142 ms
  • ap-east-2 · Taipeisoon
2 selected

Backspace removes the last label.

  • bug
  • performance
  • networking
  • security
  • documentation
  • good first issue

22 / Kanban board

Columns share borders, and a dragged card gets a hard shadow

Drag cards between columns, or focus a card and press Alt with the arrow keys. The drop slot is dashed because it's an empty space waiting for a card. A column over its WIP limit gets a warning line under its header instead of a red background.

Backlog
  • Rotate staging TLS certificates

    ORB-212securitySL
  • Document route-level timeouts

    ORB-219docsAE
In progress
  • Retry webhooks with backoff

    ORB-204bugAI
  • p95 alert per route

    ORB-207JR
  • Migrate cron to queues

    ORB-188AO
Review
  • Preview deploys for every branch

    ORB-196featureMK
Done
  • Square radio buttons

    ShippedORB-150

23 / Resizable panes

The divider is just the line

It's a 1px line with an invisible 8px hit area, and it becomes a 2px accent bar on hover, drag or focus. Arrow keys resize by 16px (64px with Shift). Enter or a double-click resets it.

send.ts
export async function send(hook, body) {
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch(hook.url, { body });
    if (res.ok) return res;
  }
}
Terminal
$ npm test -- webhooks
✓ 12 passed

24 / Editable data grid

It works like a spreadsheet

Arrow keys move the selection ring. Enter, F2, a double-click or just typing starts an edit. Enter saves and moves down, Tab moves right, and Esc cancels. Edited cells get an accent corner, and the region column checks what you type.

RowServiceRegionReplicasMemory MBOwner
1edge-routerus-east-112512Jo Rivera
2api-gatewayeu-west-281024Mina Kato
3image-proxyap-south-142048Ada Okafor
4webhook-fanoutus-east-12256Aryan Ebrahimpour
All changes saved

25 / Colour picker

A colour picker that tells you the contrast

It has a saturation and brightness field, a hue strip, a hex input and swatches. The readout also checks the colour against the page background. Picking a blue is only half the job. You also need to know whether text is readable on it.

Drag in the field or use the arrow keys on it; the hue strip is a native range input. The eyedropper button appears only where the browser supports it.

26 / Notification inbox

Unread items get a mark instead of a tint

The count on the bell uses the accent colour, because it's the one thing in the bar that needs attention. Unread items get a 6px accent square and full-strength text. Read items are muted. You can act on an item without opening it.

Open the inbox

27 / Blueprint details

Off by default, and no more than three per screen

Put these everywhere and they turn into clutter. They work best on hero sections, feature panels and empty states.

Grid substrate

8px squares at 5.5% ink. Element edges should line up with it.

Corner ticks

Registration marks

Mark two corners by default, and leave most cards without them.

Hatch fill

For placeholders and inactive areas. Boxy's version of the gray placeholder box.

Technical annotations

Small mono metadata is the easiest way to make a page look like a datasheet. Only use it for real values.

v1.1.1 · MIT · 5.6 KB GZIPPED FIG. 02 / REQUEST PATH p50 · LAST 24H · UTC