# Leumas Perspective — perspective.leumas.tech

Leumas Perspective at perspective.leumas.tech — a 3D display with nothing but a webcam: head-tracked perspective for the web. Ten kits, an image room, the @leumas/headlock SDK and a single-file...


# Leumas Perspective — perspective.leumas.tech

A 3D display with nothing but a webcam. MediaPipe FaceMesh finds the visitor's face in their own
browser, the page shifts its projection as they move, and a flat screen reads as a window. Ten kits
(seven canvas scenes, an off-axis three.js cube, an image room, a HUD parallax), the `@leumas/headlock`
SDK, and a single-file download. Free to run; a membership keeps rooms and their embed links.

Blueprint: `products/TODOS/perspective.leumas.tech.md`. Engine: `shared/packages/headlock`. API:
`products/leumas-api/src/{routes,controllers}/perspective.js` at `/api/perspective`.

## The two rules

| Rule | Where it is kept |
|---|---|
| **The camera never starts on its own, and denial latches.** | `HeadlockStage` is the only component that starts it; the stream comes from `@leumas/devices`' `requestMedia`, so a blocked camera is never re-asked; `useMediaConsent()` reports the state without asking. |
| **No frame ever leaves the tab.** | There is no upload path in the package or the site; `check:perspective-public` greps both for one on every build. The only bytes a member sends are a room's picture, once, on Save. |

## What is here

- **Engine** — `createHeadLock` (through the latch), seven built-in scenes, `createImageScene`,
  `createRoomScene`, `createCustomScene`, `runScene`, `KITS`, `createOffAxisCube` (takes `THREE`, so the
  package stays three-free), `HeadlockStage`, `useHeadLock`, `useMediaConsent`.
- **MediaPipe self-hosted** at `/perspective-mediapipe/*`, copied from the installed packages at build.
- **Pages** — `/` vitrine landing whose case IS a stage · `/kits` and `/kits/:id` · `/room` ·
  `/sdk` · `/download` (the generated `perspective-starter.html`) · `/pricing` · `/faq` · `/legal`.
  Not indexed: `/embed/:id`, `/portal`.
- **Money** — Model A, no plan row: `perspective.run` on the floor; `perspective.save` and the
  `perspective.scenes` ceiling (5 / 50 / ∞) for members. An embed answers while the owner's
  membership holds and 404s when it lapses.

## Not yet

`@leumas/headlock` is not on the public npm registry; the SDK page says so. Kept rooms are private.
The embed catalogue rows are added once the live URLs exist.

## Build and verify

```bash
pnpm --filter @leumas/perspective-web build    # vendor mediapipe → starter → og → vite → prerender → crawler files → check:perspective-public
pnpm smoke:perspective-site                     # the built site through the Imperium worker + the API seam
pnpm --filter @leumas/headlock test
```

Dev: `pnpm dev:perspective` (port 5084; leave `VITE_API_BASE` unset).


---
Source: products/leumas-perspective/README.md
Canonical: https://docs.leumas.tech/p/products/perspective-web
