Skip to content

Latest commit

 

History

62 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛰️ save-splat

An AI tool for rescue teams that takes LiDAR gaussian splat scans of collapsed buildings, measures structural damage like wall lean and debris volume, and weighs how many people might be trapped alive to rank which sites to reach first.

Demo Images

Image Image Image Image

What it does

After an earthquake, a search-and-rescue team can face dozens of collapsed buildings and only a handful of crews. The order they work the sites in decides who lives. Right now that call is usually made by looking at a leaning wall, guessing, and writing site names on a whiteboard. None of the tools involved talk to each other, and none of them turn a scan into a number you can actually compare.

save-splat takes a phone scan of a collapsed structure and pulls real measurements out of it: how far each wall leans, how the slabs and floors are angled, and how much debris is piled up. It then ranks the sites so command can see where a crew buys the most lives per hour. It measures the damage and lays out the priority. A person still makes every decision.

You load a Scaniverse or Polycam gaussian-splat .ply (a .glb or .gltf mesh works too), and the app fits planes to the walls and floors, reads the lean off each wall as a drift number, finds the ground and measures debris volume above it, and lets you place sites and rank them. There is no autopilot here. The output is a ranked list for a human to review, not a dispatch order.

Architecture

Vite React TypeScript Three.js Zod

↓

Node.js Vercel Postgres Vitest

↓

OpenRouter    OpenAI    Anthropic    Athena
Layer Technology What it handles
Frontend Vite, React 18, TypeScript The panel UI and the 3D scene, all in one page
State useSyncExternalStore store Site records live here; their 3D markers live in the viewer, keyed by id
Renderer Three.js Camera, a hand-written orbit control, site markers, and the plane overlay. Splats draw as THREE.Points
Core logic Plain TypeScript, no Three.js and no DOM Parsing, RANSAC, ranking, and export. Runs and gets tested without a browser
Parsing Custom .ply and gaussian-splat reader Reads per-Gaussian covariance from scale_* and rot_*, colour from f_dc_*, with streaming progress
Geometry Opacity-weighted RANSAC, seeded (mulberry32) Fits planes, reads wall drift bands, and measures debris volume
Validation Zod (core/swarm/schema.ts) The gate for anything coming from outside. Bad values are rejected, not clamped
Reasoner Node-only server/swarm/ Prompt, call the provider, run it through Zod, then verify
Providers OpenRouter, OpenAI, Anthropic, Athena One Reasoner interface. Whichever key is set gets used; the model comes from the account
Hosting Vercel functions, plus Vite dev and preview The same /api/swarm/* handlers run in all three
Run log Supabase Postgres pooler (optional) Appends each run to swarm_runs. A failed write logs a warning and never blocks a run

The one rule worth knowing: core/ never imports Three.js or touches the DOM. The geometry functions take plain arrays and a matrix instead of a THREE.Points object, so the measurement code can be unit-tested without a renderer.

Getting started

Prerequisites

  • Node.js 20 or newer
  • npm
  • The Stripe Projects CLI, if you want it to provision the reasoner and run-log credentials for you (optional)

1. Clone and install

git clone https://github.com/your-org/save-splat.git
cd save-splat
npm install

2. Run it

npm run dev        # http://localhost:5173

The synthetic scene loads on open, so this works with nothing else set up. Click "View demo" or open #viewer to go straight to the viewer.

3. Turn on the agent swarm (optional)

The reasoner needs one key, set server-side in .env.local. See .env.example. The quickest path pulls everything at once:

stripe projects env --pull        # writes .env.local with the real values

Or add a single key by hand:

# any one of these is enough. OpenRouter is what Stripe Projects provisions.
OPENROUTER_API_KEY=your_key
# OPENAI_API_KEY=your_key
# ANTHROPIC_API_KEY=your_key

# optional tuning
# SWARM_PROVIDER=openrouter                 # pin this when more than one key is set
# SWARM_MODEL=anthropic/claude-opus-5       # skip the catalogue lookup

# optional run log (a server-side Postgres connection string)
# SUPABASE_POOLER_URL=...
# SUPABASE_DB_PASS=...

Keep the VITE_ prefix off every secret. Vite inlines any VITE_* variable into the client bundle, so reasoner keys are read only inside server/swarm/ from process.env. The browser only ever calls /api/swarm/*.

/api/swarm/status reports what is configured, and the RUN SWARM button explains why it is disabled when nothing is set. Athena is an extra agent that Stripe Projects can provision. It works as both a reasoner and an incident reviewer, and it gets picked first when its key and MCP URL are present.

Scripts

npm run dev          # vite dev server
npm run check        # typecheck, lint, and test. Run this before you call something done
npm run test         # vitest. The core is testable without a browser
npm run build        # tsc -b && vite build, output in dist/
npm run preview      # serve the production build

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages