Barnes Vantage: how it came together.
How it came together.
- 01
The map, then the marketplace
Vantage was map-led through the summer of 2026: it opened on a map, and the first question it answered was what had been scanned near you. Checked 2026-09-11, the front door is a redirect to the marketplace instead, with the standalone full-screen map removed and the scan map folded into the scan library. Search still runs in plain language.
Product Strategy - 02
Reusing the shipped viewer, not forking one
The scan viewer runs on gaussian-splats-3d, shared with the standalone Splat Viewer through the barnes-scan-viewer package and embedded per residence, so a listing drops you straight into the full walk rather than a second app.
3D & Spatial A scan ships only if it passes. Coverage, collision and a spawn point computed from the room's own geometry, checked against a written standard before a client ever opens it. - 03
An internal standard before a scan ships
Every scan is checked against a written internal standard, coverage, collision, a spawn point computed from the room's geometry, before it earns a Verified by Vantage badge. A point-cloud minimap replaced floor plans, which misread furniture as walls.
3D & Spatial - 04
Co-browse over a self-hosted relay
A broker drives the tour; the client's browser follows over a self-hosted WebSocket relay, not a third-party vendor. Verified live: join, presence, camera state, and reactions round-trip correctly.
Backend Engineering - 05
Design matters because trust is visual
The register is a printed property dossier: an ivory ground, ink type, brass detailing and one Caslon cut carrying display and body, with figures in Fragment Mono so prices line up in a column. Light is the default and dark is a second real theme rather than an inversion, which is how the map view comes to be the dark one most buyers meet. A brokerage surface in front of a buyer has to read as finished.
Decisions on the record.
The few calls worth defending. Each one is a fork; the other branch would have been a different project.
Collapsing three broker apps into one surface
One surface with modes rather than three separate apps, so the listing a broker shows and the residence they walk are the same object, one click apart. That surface was the map until the summer of 2026; as checked on 2026-09-11 it was the marketplace, with the scan library and the viewer reached from a listing.
A self-hosted relay for co-browse
A broker-led tour needs low-latency camera sync between broker and client, but that traffic doesn't need to leave infrastructure already hosting the scans. A self-hosted WebSocket relay, co-located with the splat viewer, avoids a recurring realtime-vendor bill and keeps the stack in one place to operate.
The design system.
Tokens and treatments as they exist in the repo - values verbatim, nothing aspirational.
A printed property dossier rather than a listings site. Ivory ground, ink type, brass detailing, one Caslon cut carrying display and body, and figures set in a mono face so prices and measurements line up in a column. Nothing is rounded. Light is the default and dark is a second real theme rather than an inverted one, which matters because the map view most people arrive at is the dark one.
--bg / --bg-main#f7f3ea / #15120d- The page ground, light then dark. Ivory rather than white, which is the whole register in one value
--bg-raised / --bg-elevated / --bg-card#faf6ec / #1e1a13- Cards and panels, one step off the ground in each theme
--bg-panelrgba(247, 243, 234, 0.92) / rgba(21, 18, 13, 0.92)- Sticky and floating panels. Translucent, so the map keeps reading underneath them
--ink / --text-main#2a2620 / #f1ece1- Primary text. Warm near-black rather than black, and warm off-white rather than white
--ink-soft / --text-subtle#4a443c / #cfc7b8- Secondary text
--ink-muted / --text-muted#6c655a / #9b9384- Captions and metadata
--line#cdbfa4 / #3a342a- Hairline dividers and borders. Separation in this system is a rule, never a fill step
--line-soft#e6dec9 / #2a251c- The quieter rule, for divisions inside an already-divided panel
--accent#6f5a34 / #bd9c63- Brass, and the only accent the product has. It is asserted a second time under a doubled :root:root selector in both themes, because shared-ui ships its own --accent and this has to win
--accent-hover / --accent-dark#5f4a2c / #d8b87e- Hover, and the focus ring, since --ring resolves to it
BARNES corporate#C70A33 / #6f5a34 / #EAE6DD / #0A0A0A / #1A1A1A- --barnes-red, --barnes-gold, --barnes-grege, --barnes-ink and --barnes-charcoal. Brand surfaces only, deliberately kept out of ordinary interface work
Match scoring#3CE08F / #FFB93B / #F06050- --match-high, --match-medium and --match-low. The only place in the product allowed a saturated non-brand colour, because a score has to read as a score at a glance
.scans-ds --gold#937a4e- A scoped second system under /scans, where the viewer, map, share and compare components ported from splat-viewer still expect their old token names. --accent is re-pointed inside that subtree. A --gold token therefore exists in this repo and is not the site accent
- Display and body
AaBb Handgloves 0123
Libre Caslon TextOne family does both. app/layout.tsx loads it through next/font/google and points --font-sans and --font-serif at it, so every existing var-based rule flipped to Caslon without being edited. No Google Fonts link tag, no second family loaded per route
- Figures
AaBb Handgloves 0123
Fragment Mono--font-mono, used for prices, areas and measurements so numbers align in a column
CSS custom properties in app/globals.css, which is the single source of truth; DESIGN.md is generated from it and says so. Two things are worth knowing before touching a token. The accent is asserted a second time under a doubled :root:root selector, in both themes, because shared-ui ships its own --accent and this has to win, so the two copies move together or the themes drift. And /scans runs a separate scoped token set in app/scans/scans-theme.css under .scans-ds, so a component written for that subtree does not carry its colours outside it. There is also a legacy --color-* set kept only for backwards compatibility.
- Corners
Every Tailwind radius step collapses to 0, full included, plus a blanket .sdg :where(*) rule zeroing border-radius
The register has no rounded corners, and the CSS says so in as many words. Collapsing full too is the stricter choice than its sibling products make
- Spacing
Eleven steps, --space-1 2px through --space-11 128px: 2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128
Geometric rather than linear, so the gaps that matter at reading distance are finely spaced and the ones that separate sections are not
- Motion
One curve, --ease cubic-bezier(0.22, 1, 0.36, 1), exposed to Tailwind as the sdg timing function
A single decelerating ease for the whole product. It is the Modern House signature and it is inherited rather than chosen here
- Layout
--container is min(1480px, 92vw), --navbar-h is 72px
The container caps on the wide side because the map wants the room, and falls to a percentage before it wants a breakpoint
The design system was wrong in the repo, not just on this page
Until 2026-09-07 barnes-vantage carried a byte-identical copy of another product's DESIGN.md, headed with that product's name and describing a near-black page with a gold accent. It arrived with the monorepo split and nothing had corrected it since. Any agent or new hire following it would have built a dark gold interface for a light brass product. The fix was to rewrite the document from app/globals.css and record that the CSS wins whenever the two disagree, which is a rule worth writing down precisely because the file had already been wrong for months without anyone noticing.
Ivory rather than white, ink rather than black
The obvious light palette is white and black, and it would have made the product read as a listings site. A property dossier is printed on warm paper, and the difference between #ffffff and #f7f3ea is the whole distance between the two registers. It also means the brass accent has something to sit on. Brass on white is a beige smudge; brass on ivory is detailing.
A scoped second token set, on purpose
The /scans section runs its own system under .scans-ds because the viewer, map, share and compare components were ported wholesale from splat-viewer and expect its token names. The alternative was rewriting four working components to satisfy a naming convention. Scoping the old names to the subtree that needs them is the cheaper correct answer, and the file states the trade-off it is making: sections, not deep integration.
