rvt 0.4.0

Apache-2.0 clean-room reader for Autodesk Revit files (.rvt, .rfa, .rte, .rft) without Revit: metadata, previews and the embedded schema of 2016-2026 files, and typed elements with measured geometry from Revit 2024 and 2025 projects, exported as IFC4, glTF and plan SVG.
Documentation
# rvt-rs viewer

Zero-upload, client-side Revit viewer powered by
[`rvt-rs`](https://github.com/DrunkOnJava/rvt-rs) compiled to WebAssembly.

Hosted at <https://drunkonjava.github.io/rvt-rs/viewer/>.

Install and local build paths are documented in
[`docs/install.md`](../docs/install.md).

## Privacy posture (VW1-21)

- **Nothing leaves the browser tab.** The dropped `.rvt` / `.rfa` /
  `.rte` / `.rft` bytes are parsed in-process. There are no `fetch`,
  `XMLHttpRequest`, `WebSocket`, `EventSource`, or `sendBeacon`
  imports in the compiled WebAssembly — the CI job
  `.github/workflows/deploy-viewer.yml` fails the build if any show
  up.
- **No telemetry.** The page CSP blocks `connect-src` to everything
  except `self`, which is only needed for the static WASM bundle,
  and `blob:`, which is needed for the local GLB object URL. No
  analytics, no error reporting, no CDN font loads.
- **Browser-tested invariant.** CI runs
  `viewer/tests/no-network.spec.ts` (runtime traffic) and `viewer/tests/wasm-no-network-imports.spec.ts` (wasm-objdump import audit): it opens the built viewer,
  loads a public sample RFA, and fails with request URL plus initiator
  if any external or post-open network request occurs. See
  [`docs/viewer-privacy-posture.md`]../docs/viewer-privacy-posture.md.
- **Deterministic builds.** Every JS bundle is built from a pinned
  action SHA; the WASM comes from a pinned `wasm-pack` release.

## Local dev

```bash
# 1. Build the WASM into viewer/pkg/
(cd .. && wasm-pack build --target web --out-dir viewer/pkg -- --features wasm --no-default-features)

# 2. Install node deps
cd viewer
pnpm install --frozen-lockfile

# 3. Serve with Vite (localhost:5173)
pnpm run dev
```

Drop a Revit file onto the page, or open a redistributable demo from the
gallery (staged from `docs/viewer-demos.json` via `pnpm run stage:demos`).
Nothing is sent anywhere.

## Supported MVP workflow

1. Open a file locally (drop / picker / demo gallery).
2. Read File status: Decode confidence, Export confidence, and IFC bar.
3. Inspect decoded entities in the tree or viewport.
4. Export IFC / glTF / plan only after checking the quality label.
5. Download diagnostics for scaffold or partial exports.

Tier1 redistributable demos (`architectural-2024`, `structural-2023`,
`mep-2024`) are staged from `corpus/tier1/` via `pnpm run stage:demos`.
They open cleanly but report scaffold ~25% confidence — that is expected.
Reliable typed levels/doors/windows from arbitrary projects still depend on
Rust decoder / partition-stream work outside this viewer shell.

The `synthetic-mvp` demo is not checked in — it is generated at staging time
by the `gen-fixture` binary, so build it from the repo root first:

```bash
cargo build --release --bin gen-fixture
```

`pnpm run stage:demos` (also run by `predev` / `prebuild`) looks for the
binary on `PATH`, in `target/release/`, and in `target/debug/`. If it finds
none it runs that cargo build itself; when cargo is unavailable it warns
`synthetic-mvp: missing (gen-fixture not found …)` and the gallery marks the
demo unavailable. Nothing is downloaded either way.

## Architecture

```text
User drops .rvt
     │
     ▼
main.ts ── postMessage ──▶ worker.ts
                                │
                                ├── init wasm (pkg/rvt.js)
                                ├── openRvtBytesWithDiagnosticsMode()
                                │                         → IfcModel + diagnostics JSON
                                ├── buildSceneGraph()     → SceneNode JSON
                                ├── modelToGlb()          → Uint8Array
                                └── buildSchedule()       → Schedule JSON
                                │
                          postMessage back
                                │
                                ▼
main.ts
  ├── Three.js scene + OrbitControls + GLTFLoader
  ├── scene tree panel
  ├── category toggles
  ├── export-quality label + IFC bar selector
  ├── File status (decode / export confidence)
  ├── element-info panel (raycast picking) + host / hosted jump rows
  └── status line
```

The worker is mandatory (VW1-19) — parsing a 100 MB RFA blocks the
main thread for seconds otherwise.

## Build outputs

- `viewer/pkg/` — generated by wasm-pack (git-ignored)
- `viewer/node_modules/` — npm (git-ignored)
- `viewer/dist/` — Vite build (git-ignored)

All three are produced by the deploy workflow on every push to
`main`.